Apache HTTP Server 版本 2.4
要有效率地管理網站伺服器,有必要回報關於伺服器的活動和效能,還有問題的發生。Apache HTTP Server 提供非常全面和彈性的紀錄功能。這份文件描述如何設定它的記錄功能,以及如何了解日誌裡面的內容。
相關模組 | 相關指令 |
---|---|
Apache HTTP Server 為紀錄伺服器上發生的一切事情提供各種不同機制,從最初的要求、經過 URL 對應程序,到最後的連線解決,包括在處理程序中發生的錯誤。此外,協力廠商模組可能會提供記錄功能,或把項目插入到現有的日誌檔案,而應用程式如 CGI 程式、PHP 指令碼,或其他處理常式,可能會傳送訊息到伺服器的錯誤日誌。
在本文檔中,我們討論包含在 http 伺服器之中標準部分的記錄模組。
任何能夠寫入 Apache httpd 寫入日誌檔案目錄的人,幾乎可以確定能存取伺服器啟動的 uid,通常是 root。不要在不知道後果的情況下,授予人們寫入日誌檔案儲存目錄的權限;請查看安全秘訣文件查看詳細資訊。
此外,記錄檔可能包含未經跳脫處理,由用戶端直接提供資訊。因此,惡意用戶端有可能插入控制字元到記錄檔中,所以處理原始記錄檔時需小心謹慎。
相關模組 | 相關指令 |
---|---|
伺服器錯誤記錄檔(由指令碼 ErrorLog
設定名稱和位置)是最重要的記錄檔。Apache httpd 會將診斷資訊傳送至這個記錄檔,並將處理請求時所遭遇的任何錯誤記錄下來。當伺服器發生起動問題或運作問題時,最先會檢視的便是這個記錄檔,因為這個記錄檔通常會顯示錯誤詳細資訊以及修復方法。
錯誤記錄檔通常會寫入一個檔案中(在 Unix 系統中通常為 error_log
,在 Windows 和 OS/2 中通常為 error.log
)。在 Unix 系統中,伺服也可以將錯誤傳送到 syslog
或 傳遞至某個程式。
錯誤記錄檔的格式由指令碼 ErrorLogFormat
定義,你可以使用此指令碼自訂記錄的數值。如果你未設定值,預設會定義一個格式。典型的記錄訊息範例:
[2011 年 9 月 9 日星期五上午 10:42:29.902022] [核心:錯誤] [程序 ID 35708:執行緒 ID 4328636416] [用戶端 72.15.99.187] 檔案不存在:/usr/local/apache2/htdocs/favicon.ico
記錄條目中的第一個項目是訊息的日期和時間。下一項是由哪個模組產生該訊息(本例為核心)以及哪個訊息的嚴重性等級。接著是由哪個程序處理這項條件的程序 ID 和(如果需要)執行緒 ID。接著是提出請求的用戶端位址。最後一是詳細的錯誤訊息,本例指出請求的檔案不存在。
各種不同的訊息會顯示在錯誤記錄檔中。大多數的訊息如下例所示。錯誤記錄檔也包含 CGI 腳本的偵錯輸出。CGI 腳本寫入 stderr
的任何資訊都會直接複製到錯誤記錄檔。
在錯誤記錄檔和連線記錄檔中放入 %L
權杖會產生一個記錄條目 ID,你可以利用此 ID 將錯誤記錄檔中的條目與連線記錄檔中的條目關聯起來。如果載入 mod_unique_id
,其唯一的請求 ID 也會用作記錄條目 ID。
測試時,持續監控錯誤記錄檔以找出任何問題通常非常有用。在 Unix 系統中,你可以使用下列指令達成此目的:
tail -f error_log
LogLevel
指令讓您能對每一個模組指定日誌記錄等級。這樣一來,如果您在排除特定模組問題,您可以在不記錄其他您不感興趣的模組的情況下,將其記錄程式加大。這對於 mod_proxy
或 mod_rewrite
等模組特別有用,對於您想要知道其嘗試執行的細節時更是如此。
在 LogLevel
指令中指定模組名稱即可。
LogLevel info rewrite:trace5
這會將主要的 LogLevel
設為資訊,但會將 mod_rewrite
的 LogLevel
設為 trace5
。
RewriteLog
,等每個模組的記錄指令。相關模組 | 相關指令 |
---|---|
伺服器存取記錄會記錄伺服器處理的所有要求。存取記錄的位置和內容由 CustomLog
指令控制。LogFormat
指令可用於簡化記錄內容的選取。此章節說明如何設定伺服器,以便在存取記錄中記錄資訊。
將資訊儲存在存取記錄僅是記錄管理的第一步。下一步是分析此資訊以產生有用的統計資訊。整體來說,記錄分析超出了本文的範圍,也不算是網路伺服器本身的工作。
各種版本的 Apache httpd 使用了其他模組和指令控制存取記錄,包括 mod_log_referer、mod_log_agent,以及 TransferLog
指令。CustomLog
指令現在包含所有舊指令的功能。
存取記錄的格式可選擇性極高。格式是使用格式化字串指定的,其看來非常像 C 風格的 printf(1) 格式化字串。下一個章節會提供一些範例。有關格式化字串可能內容的完整清單,請參閱 mod_log_config
格式化字串。
以下是存取記錄的典型設定。
LogFormat "%h %l %u %t \"%r\" %>s %b" common CustomLog logs/access_log common
這會定義暱稱common
並把它關聯到特定日誌格式字串,格式字串由百分比指令組成,每個指令都告訴伺服器記錄特定資訊,字面字元也可以放入格式字串,並會直接複製到日誌輸出版中,引號字元("
)必須在前面加上反斜線以免被解釋成格式字串的結尾,格式字串也可能包含以下特殊控制字元:「\n
」代表換行,「\t
」代表跳格。
CustomLog
指令使用已定義的暱稱設定新的日誌檔案,瀏覽紀錄的檔案名稱相對於 ServerRoot
,除非檔案名稱開頭為斜線。
以上的組態會以共通紀錄格式 (Common Log Format, CLF) 記錄日誌條目,這種標準格式可以用許多不同的網路伺服器產生,並使用許多日誌分析程式讀取,CLF產生的日誌檔案條目看起來會像這樣:
127.0.0.1 - frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326
這則日誌條目中的每一部分說明如下。
127.0.0.1
(%h
)HostnameLookups
設為開啟
,伺服器會試著判定主機名稱並記錄在 IP 位址中,不過,並不建議這種組態,因為這樣會顯著拖慢伺服器,您最好使用 logresolve
等日誌後處理器來判定主機名稱,這裡報告的IP 位址不一定使用者的電腦的位置,如果用戶端和伺服器之間有代理伺服器,這個位址會是代理伺服器的位址,而不是原始電腦的。-
(%l
)IdentityCheck
設為開啟
,否則 Apache httpd 甚至不會嘗試判定資訊。frank
(%u
)
[d/m/y:h:m:s 區段]
d = 2*位元組
m = 3*字母
y = 4*位元組
h = 2*位元組
m = 2*位元組
s = 2*位元組
區段 = (+ | -)4*位元組
可以藉由在記錄格式字串中指定「%{format}t」,以其他格式顯示時間,其中「format」為 C 標準函式庫中的「strftime(3)」,或是其中一個受支持的特殊權杖。詳細資訊請見「mod_log_config
」格式字串。
另一種常用的格式字串稱為複合記錄格式。使用方法如下:
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" combined CustomLog log/access_log combined
此格式與一般記錄格式完全相同,只多加了兩個欄位。各附加欄位都使用百分比指令「%{header}i」,其中「header」是可以是任何 HTTP 請求標頭。根據此格式的存取記錄會看起來像這樣
127.0.0.1 - frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326 "http://www.example.com/start.html" "Mozilla/4.08 [en] (Win98; I ;Nav)"
其他欄位如下
"http://www.example.com/start.html"
(\"%{Referer}i\"
)/apache_pb.gif
或包含該檔案的網頁。)"Mozilla/4.08 [en] (Win98; I ;Nav)"
(\"%{User-agent}i\"
)只要在設定檔中指定多個指令 CustomLog
即可建立多個存取記錄。例如,下列指令將建立三個存取記錄。第一個包含基本的 CLF 資訊,而第二和第三個包含轉介資訊和瀏覽器資訊。最後兩個指令 CustomLog
顯示如何模仿指令 ReferLog
和 AgentLog
的效果。
LogFormat "%h %l %u %t \"%r\" %>s %b" common CustomLog logs/access_log common CustomLog logs/referer_log "%{Referer}i -> %U" CustomLog logs/agent_log "%{User-agent}i"
此範例也顯示使用指令 LogFormat
定義別名不必要。LogFormat 可以直接在指令 CustomLog
中指定。
有時候,根據客戶端要求的特性從存取記錄中排除特定條目很方便。可輕鬆使用 環境變數 達成。首先,必須設定環境變數以指出要求符合特定條件。通常會使用 SetEnvIf
完成。接下來使用指令 CustomLog
的 env=
子句包含或排除已設定環境變數的要求。一些範例
# Mark requests from the loop-back interface SetEnvIf Remote_Addr "127\.0\.0\.1" dontlog # Mark requests for the robots.txt file SetEnvIf Request_URI "^/robots\.txt$" dontlog # Log what remains CustomLog logs/access_log common env=!dontlog
再舉一個例子,考量將英文人士的要求記錄到一個記錄檔,而將非英文人士的要求記錄到另一個記錄檔。
SetEnvIf Accept-Language "en" english CustomLog logs/english_log common env=english CustomLog logs/non_english_log common env=!english
在快取情況下,您會想知道快取的效率。以下是找出它的非常簡單方法
SetEnv CACHE_MISS 1 LogFormat "%h %l %u %t "%r " %>s %b %{CACHE_MISS}e" common-cache CustomLog logs/access_log common-cache
mod_cache
會在 mod_env
之前執行,如果成功,將不提供內容。在這種情況下,快取命中會記錄 -
,而快取未命中會記錄 1
。
除了 env=
語法外,LogFormat
還支援在 HTTP 回應代碼中記錄值條件
LogFormat "%400,501{User-agent}i" browserlog LogFormat "%!200,304,302{Referer}i" refererlog
在第一個範例中,如果 HTTP 狀態碼是 400 或 501,將會記錄 使用者代理程式
。其他情況,將會記錄連字符號 "-" 取代。以此類推,在第二個範例中,如果 HTTP 狀態碼不是 200、304,或 302,將會記錄 HTTP 來源
。(請注意狀態碼之前的驚嘆號。)
儘管我們剛剛已說明條件式記錄非常強大且彈性,但它並非控制日誌內容的唯一方式。日誌檔案包含伺服器活動的完整記錄時會更有用。通常最簡單的方式是將日誌檔案後處理,移除您不想考慮的要求。
即便是在負荷不大的伺服器上,儲存在日誌檔中的資訊量也非常龐大。存取日誌檔案的容量通常會每 10,000 個要求增加 1 MB 以上。因此必須定期輪換日誌檔案,方法是移動或刪除現有日誌。當伺服器正在執行時無法執行此動作,因為只要 Apache httpd 維持檔案開啟,就會持續寫入舊日誌檔案。取而代之的是,伺服器必須在移動或刪除日誌檔案之後重新啟動,其才會開啟新的日誌檔案。
透過使用優雅的重新啟動,可發布指令讓伺服器開啟新的日誌檔而不會失去任何來自客戶端的現有或待處理連線。不過,若要達成此目的,伺服器必須在服務舊要求的同時持續寫入舊日誌檔。因此,在重新啟動之後必須等一段時間,才能對日誌檔執行任何處理。一個只會輪換日誌並壓縮舊日誌以節省空間的典型範例為
mv access_log access_log.old
mv error_log error_log.old
apachectl graceful
sleep 600
gzip access_log.old error_log.old
執行日誌輪換的另一種方式是使用管道日誌,如下一節所述。
Apache httpd 有能力透過管道將錯誤和存取日誌寫入另一個程序,而不是直接輸出到檔案。這種能力大幅提升了記錄的彈性,而且無需加入任何程式碼到主伺服器。若要將日誌寫入管道,只要將檔案名稱取代為管道字元 "|
",然後再接上可接受其標準輸入中日誌輸入項目的可執行檔名稱。伺服器在啟動時將啟動管道日誌程序,而且若程式在伺服器執行時崩潰,伺服器也會重新啟動該程式。(由於後項功能,我們可以將此技術稱為「可靠的管道記錄」)
管線日誌處理程序是由母項 Apache httpd 處理程序衍生的,並繼承該處理程序的 user id。這表示管線日誌程式通常以根執行。因此,保持程式簡單且安全非常重要。
管線日誌的一個重要用途是允許日誌輪替,無需重新啟動伺服器。為此,Apache HTTP Server 包含一個稱為 rotatelogs
的簡單程式。例如,若要每 24 小時輪替日誌,您可以使用
CustomLog "|/usr/local/apache/bin/rotatelogs /var/log/access_log 86400" common
請注意,引號用於封裝會呼叫管線的完整命令。儘管這些範例是針對存取日誌,但相同技術也可以用於錯誤日誌。
與條件式記錄一樣,管線日誌是一個非常強大的工具,但如果可以使用較簡單的解決方案(如離線後處理),則不應使用它們。
預設情況下,管線日誌處理程序衍生時不會呼叫 shell。使用「|$
」代替「|
」以使用 shell 衍生(通常使用 /bin/sh -c
)
# Invoke "rotatelogs" using a shell CustomLog "|$/usr/local/apache/bin/rotatelogs /var/log/access_log 86400" common
這是 Apache 2.2 的預設行為。根據 shell 規格,這可能會導致記錄管線程式運行過程中產生額外的 shell 處理程序,並在重新啟動時產生訊號處理問題。為了與 Apache 2.2 相容,也支援並等同於使用「|
」的記號「||
」。
請注意,在 Windows 上,當執行許多管線記錄器處理程序(尤其是在 HTTPD 以服務身份執行的狀況)時,您可能會遇到問題。這是因為用罄了桌面堆積空間所導致。提供的桌面堆積空間給每個服務是由 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SessionManager\SubSystems\Windows 註冊值中 SharedSection
參數的第三個參數來指定的。請謹慎變更此值;變更 Windows 註冊表的正常注意事項適用,但如果數字調整得太高,您也可能耗盡桌面堆積空間池。
當執行具有許多 虛擬主機 的伺服器時,有幾個選項可以處理日誌檔案。首先,可以在單主機伺服器中完全相同的方式使用日誌。只要將記錄指令置於主伺服器內容中 <VirtualHost>
部分外部,即可在同一個存取日誌和錯誤日誌中記錄所有要求。此技術不允許輕鬆收集個別虛擬主機的統計資料。
如果 CustomLog
或 ErrorLog
指令放在 <VirtualHost>
區段內,那這個虛擬主機的所有要求或錯誤將只記錄到指定的檔案。任何沒有記錄指令的虛擬主機,其要求仍會傳送到主伺服器記錄。這個技術對少數虛擬主機來說很有用,但如果主機數量非常多,管理上可能會很複雜。此外,通常會造成 檔案描述符不足 的問題。
對存取記錄來說,有個很好的折衷方法。藉由將虛擬主機的資訊加入記錄格式字串,可以將所有主機記錄到同一個記錄中,稍後再將記錄分割成個別檔案。例如,考慮下列指令。
LogFormat "%v %l %u %t \"%r\" %>s %b" comonvhost CustomLog logs/access_log comonvhost
%v
用於記錄提供請求服務的虛擬主機名稱。然後像 split-logfile 這樣的程式可以用於後處理存取記錄,以便將其分割成每個虛擬主機一個檔案。
相關模組 | 相關指令 |
---|---|
mod_logio
新增了兩個附加的 LogFormat
欄位(%I 和 %O),用於記錄實際在網路中接收和傳送的位元組數目。
mod_log_forensic
提供鑑識客戶端請求的記錄。記錄在處理請求之前和之後完成,因此鑑識記錄包含每個請求的兩個記錄列。鑑識記錄器非常嚴格,沒有任何自訂。它可以成為非常有用的偵錯和安全性工具。
啟動時,Apache httpd 會將父 httpd 處理程序的處理程序識別碼儲存在檔案 logs/httpd.pid
中。這個檔案名稱可以使用 PidFile
指令變更。處理程序識別碼由管理員用於重新啟動和終止守護程式,方法是將訊號傳送給父處理程序;在 Windows 上,改用 -k 命令列選項。如需更多資訊,請參閱 停止和重新啟動 頁面。
ScriptLog
指令讓您可以記錄 CGI 腳本的輸入和輸出來協助偵錯。只能在測試時使用這個功能,不要用於實體伺服器。更多資訊可在 mod_cgi 文件中找到。