為了有效地管理Web伺服器,有必要獲得有關伺服器的活動和效能以及可能發生的任何問題的反饋。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
指令定義,可以使用該指令自定義記錄的值。如果未指定預設格式,則預設為格式。典型的紀錄檔訊息如下:
[Fri Sep 09 10:42:29.902022 2011] [core:error] [pid 35708:tid 4328636416] [client 72.15.99.187] File does not exist: /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
設定為info
,但將其設定為trace5
以獲取mod_rewrite
。
伺服器存取紀錄檔記錄伺服器處理的所有請求。存取紀錄檔的位置和內容由CustomLog
指令控制。LogFormat
指令可用於簡化紀錄檔內容的選擇。本節介紹如何組態伺服器以在存取紀錄檔中記錄資訊。
當然,將資訊儲存在存取紀錄檔中只是紀錄檔管理的開始。下一步是分析此資訊以生成有用的統計資訊。一般而言,紀錄檔分析超出了本文件的範圍,並不是Web伺服器本身的部分工作。
各種版本的Apache httpd使用其他模組和指令來控制存取紀錄檔記錄,包括mod_log_referer
,mod_log_agent
和TransferLog
指令。CustomLog
指令現在包含所有舊指令的功能。
存取紀錄檔的格式是高度可組態的。使用格式字串指定格式,該字串看起來很像C樣式的printf(1)格式字串。
通用紀錄檔格式
存取紀錄檔的典型組態可能如下所示-
LogFormat "%h %l %u %t "%r" %>s %b" common
CustomLog logs/access_log common
這定義了暱稱common
,並將其與特定的紀錄檔格式字串相關聯。格式字串由百分比指令組成,每個指令指示伺服器記錄特定的資訊。文字字元也可以放在格式字串中,並直接複製到紀錄檔輸出中。引號字元("
)必須通過在它前面放一個反斜槓來跳脫,以防止它被解釋為格式字串的結尾。格式字串也可能包含特殊控制字元\n
表示換行符和\t
為標籤。
CustomLog
指令使用定義的暱稱設定新的紀錄檔檔案。存取紀錄檔的檔案名相對於ServerRoot
,除非它以斜槓開頭。
上述組態將以稱為通用紀錄檔格式(CLF)的格式寫入紀錄檔條目。這種標準格式可以由許多不同的Web伺服器生成,並由許多紀錄檔分析程式讀取。CLF
中生成的紀錄檔檔案條目如下所示:
127.0.0.1 - frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326
組合紀錄檔格式
另一種常用的格式字串稱為組合紀錄檔格式,它可以如下使用。
LogFormat "%h %l %u %t "%r" %>s %b "%{Referer}i" "%{User-agent}i"" combined
CustomLog log/access_log combined
此格式與通用紀錄檔格式完全相同,另外還新增了兩個欄位。每個附加欄位都使用percent-directive%{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)"
多個存取紀錄檔
只需在組態檔案中指定多個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"
條件紀錄檔
有時,根據用戶端請求的特徵從存取紀錄檔中排除某些條目是方便的。這可以通過環境變數輕鬆完成。首先,必須設定環境變數以指示請求滿足特定條件。通常通過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,204或302,則將記錄Referer
。
即使是在中等繁忙的伺服器上,紀錄檔檔案中儲存的資訊量也非常大。存取紀錄檔檔案通常每10,000個請求增長1MB或更多。因此,有必要通過移動或刪除現有紀錄檔來定期輪換紀錄檔檔案。這在伺服器執行時無法完成,因為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進程生成,並繼承該進程的使用者標識。這意味著管道紀錄檔程式通常以root身份執行。因此,保持程式簡單安全非常重要。
管道紀錄檔的一個重要用途是允許紀錄檔輪換而無需重新啟動伺服器。為此,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的相容性原因,符號||
也支援並等同於使用|
。
執行具有許多虛擬主機的伺服器時,有幾個選項可用於處理紀錄檔檔案。首先,可以使用與單主機伺服器完全相同的紀錄檔。只需將紀錄檔記錄指令放在主伺服器上下文中的<VirtualHost>
部分之外,就可以在同一存取紀錄檔和錯誤紀錄檔中記錄所有請求。此技術不允許在單個虛擬主機上輕鬆收集統計資訊。
如果將CustomLog
或ErrorLog
指令放在<VirtualHost>
部分中,則該虛擬主機的所有請求或錯誤將僅記錄到指定的檔案。任何沒有紀錄檔記錄指令的虛擬主機仍會將其請求傳送到主伺服器紀錄檔。此技術對於少量虛擬主機非常有用,但如果主機數量非常大,則管理起來可能很複雜。此外,它通常會產生檔案描述符不足的問題。
對於存取紀錄檔,有一個非常好的折衷方案。通過將虛擬主機上的資訊新增到紀錄檔格式字串,可以將所有主機記錄到同一紀錄檔中,然後將紀錄檔拆分為單個檔案。例如,請考慮以下指令。
LogFormat "%v %l %u %t \"%r\" %>s %b" comonvhost
CustomLog logs/access_log comonvhost
%v
用於記錄為請求提供服務的虛擬主機的名稱。然後,可以使用像split-logfile
這樣的程式對存取紀錄檔進行後處理,以便將其分成每個虛擬主機的一個檔案。