Apache HTTP Server提供了各種不同的機(jī)制,用于記錄服務(wù)器上發(fā)生的所有事情,從初始請求到URL映射過程,再到最終的連接解決方案,包括流程中可能發(fā)生的任何錯誤。除此之外,第三方模塊可以提供日志記錄功能,或者將條目注入到現(xiàn)有日志文件中,并且諸如CGI程序或PHP腳本或其他處理程序之類的應(yīng)用程序可以向服務(wù)器錯誤日志發(fā)送消息。
在本文中,我們將討論作為http服務(wù)器標(biāo)準(zhǔn)部分的日志記錄模塊。
安全警告
任何能夠?qū)懭階pache httpd正在編寫日志文件的目錄的用戶幾乎可以訪問服務(wù)器啟動的uid,通常是root用戶。不要在不知道后果的情況下對存儲日志的目錄進(jìn)行寫訪問;。
此外,日志文件可能包含客戶端直接提供的信息,而不會轉(zhuǎn)義。因此,惡意客戶端可能會在日志文件中插入控制字符,因此在處理原始日志時必須小心。
錯誤日志
服務(wù)器錯誤日志(其名稱和位置由ErrorLog
指令設(shè)置)是最重要的日志文件。這是Apache httpd將發(fā)送診斷信息并記錄它在處理請求時遇到的任何錯誤的地方。當(dāng)啟動服務(wù)器或服務(wù)器操作出現(xiàn)問題時,它是第一個查看的地方,因?yàn)樗ǔ0e誤的詳細(xì)信息以及如何修復(fù)它。
錯誤日志通常寫入文件(通常是Unix系統(tǒng)上的error_log和Windows和OS/2上的error.log
)。在Unix系統(tǒng)上,也可以讓服務(wù)器向syslog
發(fā)送錯誤或?qū)⑺鼈儌鬟f給程序。
錯誤日志的格式由ErrorLogFormat
指令定義,可以使用該指令自定義記錄的值。如果未指定默認(rèn)格式,則默認(rèn)為格式。典型的日志消息如下:
[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
Shell
日志條目中的第一項(xiàng)是消息的日期和時間。接下來是生成消息的模塊(在本例中為核心)以及該消息的嚴(yán)重性級別。接下來是經(jīng)歷該條件的進(jìn)程ID以及(如果適用的話)線程ID。接下來,我們有發(fā)出請求的客戶端地址。最后是詳細(xì)的錯誤消息,在這種情況下表示對不存在的文件的請求。
錯誤日志中可能會出現(xiàn)各種各樣的不同消息。大多數(shù)看起來類似于上面的例子。錯誤日志還將包含CGI腳本的調(diào)試輸出。通過CGI腳本寫入stderr
的任何信息都將直接復(fù)制到錯誤日志中。
在錯誤日志和訪問日志中放置%L
標(biāo)識符將生成一個日志條目ID,您可以使用該ID將錯誤日志中的條目與訪問日志中的條目相關(guān)聯(lián)。如果加載了mod_unique_id
,則其唯一請求ID也將用作日志條目ID。
在測試期間,連續(xù)監(jiān)視錯誤日志以查找任何問題通常很有用。在Unix系統(tǒng)上,您可以使用以下方法完成此操作 -
$ tail -f error_log
Shell
按模塊記錄日志
LogLevel
指令用于基于每個模塊指定日志嚴(yán)重性級別。通過這種方式,如果您只使用一個特定模塊來解決問題,則可以調(diào)高其日志記錄量,而無需獲取不感興趣的其他模塊的詳細(xì)信息。這對于mod_proxy
或mod_rewrite
等模塊特別有用。你想知道它想要做什么的細(xì)節(jié)。
通過在LogLevel
指令中指定模塊的名稱來執(zhí)行此操作:
LogLevel info rewrite:trace5
Shell
這會將主LogLevel
設(shè)置為info
,但將其設(shè)置為trace5
以獲取mod_rewrite
。
訪問日志
服務(wù)器訪問日志記錄服務(wù)器處理的所有請求。訪問日志的位置和內(nèi)容由CustomLog
指令控制。LogFormat
指令可用于簡化日志內(nèi)容的選擇。本節(jié)介紹如何配置服務(wù)器以在訪問日志中記錄信息。
當(dāng)然,將信息存儲在訪問日志中只是日志管理的開始。下一步是分析此信息以生成有用的統(tǒng)計信息。一般而言,日志分析超出了本文檔的范圍,并不是Web服務(wù)器本身的部分工作。
各種版本的Apache httpd使用其他模塊和指令來控制訪問日志記錄,包括mod_log_referer
,mod_log_agent
和TransferLog
指令。CustomLog
指令現(xiàn)在包含所有舊指令的功能。
訪問日志的格式是高度可配置的。使用格式字符串指定格式,該字符串看起來很像C樣式的printf(1)格式字符串。
通用日志格式
訪問日志的典型配置可能如下所示-
LogFormat "%h %l %u %t "%r" %>s %b" common CustomLog logs/access_log common
Shell
這定義了昵稱common
,并將其與特定的日志格式字符串相關(guān)聯(lián)。格式字符串由百分比指令組成,每個指令指示服務(wù)器記錄特定的信息。文字字符也可以放在格式字符串中,并直接復(fù)制到日志輸出中。引號字符("
)必須通過在它前面放一個反斜杠來轉(zhuǎn)義,以防止它被解釋為格式字符串的結(jié)尾。格式字符串也可能包含特殊控制字符\n
表示換行符和\t
為標(biāo)簽。
CustomLog
指令使用定義的昵稱設(shè)置新的日志文件。訪問日志的文件名相對于ServerRoot
,除非它以斜杠開頭。
上述配置將以稱為通用日志格式(CLF)的格式寫入日志條目。這種標(biāo)準(zhǔn)格式可以由許多不同的Web服務(wù)器生成,并由許多日志分析程序讀取。CLF
中生成的日志文件條目如下所示:
127.0.0.1 - frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326
Shell
組合日志格式
另一種常用的格式字符串稱為組合日志格式,它可以如下使用。
LogFormat "%h %l %u %t "%r" %>s %b "%{Referer}i" "%{User-agent}i"" combined CustomLog log/access_log combined
Shell
此格式與通用日志格式完全相同,另外還添加了兩個字段。每個附加字段都使用percent-directive%{header}i
,其中header
可以是任何HTTP請求標(biāo)頭。此格式下的訪問日志如下所示:
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)"
Shell
多個訪問日志
只需在配置文件中指定多個CustomLog
指令即可創(chuàng)建多個訪問日志。例如,以下指令將創(chuàng)建三個訪問日志。第一個包含基本的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"
Shell
條件日志
有時,根據(jù)客戶端請求的特征從訪問日志中排除某些條目是方便的。這可以通過環(huán)境變量輕松完成。首先,必須設(shè)置環(huán)境變量以指示請求滿足特定條件。通常通過SetEnvIf
完成。然后,CustomLog
指令的env =
子句用于包含或排除設(shè)置環(huán)境變量的請求。一些例子:
# 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
Shell
作為另一個示例,考慮將來自英語用戶的請求記錄到一個日志文件,將非英語用戶記錄到不同的日志文件。
SetEnvIf Accept-Language "en" english CustomLog logs/english_log common env=english CustomLog logs/non_english_log common env=!english
Shell
在緩存場景中,如果想知道緩存的效率。一個非常簡單的方法是:
SetEnv CACHE_MISS 1 LogFormat "%h %l %u %t "%r " %>s %b %{CACHE_MISS}e" common-cache CustomLog logs/access_log common-cache
Shell
mod_cache
將在mod_env
之前運(yùn)行,并且在成功時將在沒有它的情況下傳遞內(nèi)容。在這種情況下,緩存命中將記錄 - 而緩存未命中將記錄1。
除了env =
語法之外,LogFormat還支持以HTTP響應(yīng)代碼為條件的日志記錄值:
LogFormat "%400,501{User-agent}i" browserlog LogFormat "%!200,304,302{Referer}i" refererlog
Shell
在第一個示例中,如果HTTP狀態(tài)代碼為400或501,則將記錄用戶代理。在其他情況下,將記錄文字-
。同樣,在第二個示例中,如果HTTP狀態(tài)代碼不是200,204或302,則將記錄Referer
。
記錄輪換
即使是在中等繁忙的服務(wù)器上,日志文件中存儲的信息量也非常大。訪問日志文件通常每10,000個請求增長1MB或更多。因此,有必要通過移動或刪除現(xiàn)有日志來定期輪換日志文件。這在服務(wù)器運(yùn)行時無法完成,因?yàn)锳pache httpd將繼續(xù)寫入舊的日志文件,只要它保持文件打開即可。相反,必須在移動或刪除日志文件后重新啟動服務(wù)器,以便它將打開新的日志文件。
通過使用正常重新啟動,可以指示服務(wù)器打開新的日志文件,而不會丟失來自客戶端的任何現(xiàn)有或掛起的連接。但是,為了實(shí)現(xiàn)此目的,服務(wù)器必須在完成舊請求的服務(wù)時繼續(xù)寫入舊日志文件。因此,在對日志文件進(jìn)行任何處理之前,必須在重新啟動后等待一段時間。簡單地旋轉(zhuǎn)日志并壓縮舊日志以節(jié)省空間的典型方案是:
mv access_log access_log.old mv error_log error_log.old apachectl graceful sleep 600 gzip access_log.old error_log.old
Shell
管道日志
Apache httpd能夠通過管道將錯誤和訪問日志文件寫入另一個進(jìn)程,而不是直接寫入文件。此功能可顯著提高日志記錄的靈活性,而無需向主服務(wù)器添加代碼。要將日志寫入管道,只需使用管道符“|”替換文件名,然后替換應(yīng)接受其標(biāo)準(zhǔn)輸入上的日志條目的可執(zhí)行文件的名稱。服務(wù)器啟動時服務(wù)器將啟動管道日志進(jìn)程,如果在服務(wù)器運(yùn)行時崩潰,它將重新啟動它。
管道日志進(jìn)程由父Apache httpd進(jìn)程生成,并繼承該進(jìn)程的用戶標(biāo)識。這意味著管道日志程序通常以root身份運(yùn)行。因此,保持程序簡單安全非常重要。
管道日志的一個重要用途是允許日志輪換而無需重新啟動服務(wù)器。為此,Apache HTTP Server包含一個名為rotatelogs
的簡單程序。例如,要每24小時輪換一次日志,您可以使用:
CustomLog "|/usr/local/apache/bin/rotatelogs /var/log/access_log 86400" common
Shell
請注意,引號用于包含將為管道調(diào)用的整個命令。雖然這些示例適用于訪問日志,但相同的技術(shù)可用于錯誤日志。
與條件日志記錄一樣,管道日志是一種非常強(qiáng)大的工具,但是如果可以使用更簡單的解決方案(如離線后處理),則不應(yīng)使用它們。
默認(rèn)情況下,在不調(diào)用shell的情況下生成管道日志進(jìn)程。使用|$
代替|
使用shell生成(通常使用/bin/sh -c
):
# Invoke "rotatelogs" using a shell CustomLog "|$/usr/local/apache/bin/rotatelogs /var/log/access_log 86400" common
Shell
這是Apache 2.2的默認(rèn)行為。根據(jù)shell的具體情況,這可能會導(dǎo)致日志記錄管道程序的生命周期內(nèi)的額外shell進(jìn)程以及重新啟動期間的信號處理問題。出于與Apache 2.2的兼容性原因,符號||
也支持并等同于使用|
。
虛擬主機(jī)日志
運(yùn)行具有許多虛擬主機(jī)的服務(wù)器時,有幾個選項(xiàng)可用于處理日志文件。首先,可以使用與單主機(jī)服務(wù)器完全相同的日志。只需將日志記錄指令放在主服務(wù)器上下文中的<VirtualHost>
部分之外,就可以在同一訪問日志和錯誤日志中記錄所有請求。此技術(shù)不允許在單個虛擬主機(jī)上輕松收集統(tǒng)計信息。
如果將CustomLog
或ErrorLog
指令放在<VirtualHost>
部分中,則該虛擬主機(jī)的所有請求或錯誤將僅記錄到指定的文件。任何沒有日志記錄指令的虛擬主機(jī)仍會將其請求發(fā)送到主服務(wù)器日志。此技術(shù)對于少量虛擬主機(jī)非常有用,但如果主機(jī)數(shù)量非常大,則管理起來可能很復(fù)雜。此外,它通常會產(chǎn)生文件描述符不足的問題。
對于訪問日志,有一個非常好的折衷方案。通過將虛擬主機(jī)上的信息添加到日志格式字符串,可以將所有主機(jī)記錄到同一日志中,然后將日志拆分為單個文件。例如,請考慮以下指令。
LogFormat "%v %l %u %t \"%r\" %>s %b" comonvhost CustomLog logs/access_log comonvhost
Shell
%v
用于記錄為請求提供服務(wù)的虛擬主機(jī)的名稱。然后,可以使用像split-logfile
這樣的程序?qū)υL問日志進(jìn)行后處理,以便將其分成每個虛擬主機(jī)的一個文件。
更多建議: