Log Files

为了有效地 Management Web 服务器,有必要获取有关服务器活动和性能以及可能出现的任何问题的反馈。 Apache HTTP Server 提供了非常全面和灵活的日志记录功能。本文档介绍了如何配置其日志记录功能以及如何理解日志包含的内容。

Overview

Related Modules Related Directives
mod_log_config
mod_log_forensic
mod_logio
mod_cgi

Apache HTTP Server 提供了多种不同的机制来记录服务器上发生的所有事情,从最初的请求到 URL Map 过程,再到连接的最终解决,包括过程中可能发生的任何错误。除此之外,第三方模块还可以提供日志记录功能,或将条目注入到现有的日志文件中,并且诸如 CGI 程序,PHP 脚本或其他处理程序之类的应用程序可以向服务器错误日志发送消息。

在本文档中,我们讨论作为 http 服务器标准部分的日志记录模块。

Security Warning

可以写入 Apache httpd 写入日志文件的目录的任何人几乎都可以访问服务器启动时所使用的 uid(通常是 root)。 不要让人们在不知道后果的情况下对日志存储的目录进行写访问;有关详细信息,请参见security tips文档。

另外,日志文件可能包含 Client 端直接提供的信息,不会转义。因此,恶意 Client 端有可能在日志文件中插入控制字符,因此在处理原始日志时必须格外小心。

Error Log

Related Modules Related Directives
core ErrorLog
ErrorLogFormat
LogLevel

最重要的日志文件是服务器错误日志,该日志的名称和位置由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(如果适用)。接下来,我们有发出请求的 Client 地址。最后是详细的错误消息,在这种情况下,该错误消息表示请求的文件不存在。

错误日志中会出现各种各样的不同消息。大多数看起来类似于上面的示例。错误日志还将包含 CGI 脚本的调试输出。 CGI 脚本写入stderr的任何信息都将直接复制到错误日志中。

在错误日志和访问日志中都放入%L令牌将产生日志条目 ID,您可以使用该 ID 将错误日志中的条目与访问日志中的条目相关联。如果加载了mod_unique_id,则其唯一的请求 ID 也将用作日志条目 ID。

在测试过程中,连续监视错误日志中是否存在任何问题通常很有用。在 Unix 系统上,可以使用以下方法完成此操作:

tail -f error_log

Per-module logging

LogLevel伪指令使您可以按模块指定日志严重性级别。这样,如果您仅对一个特定模块的问题进行故障排除,则可以调高其日志记录量,而无需获取其他您不感兴趣的模块的详细信息。这对于mod_proxymod_rewrite等模块特别有用您想知道有关它要做什么的详细信息。

通过在LogLevel指令中指定模块名称来执行此操作:

LogLevel info rewrite:trace5

这会将主LogLevel设置为 info,但将其设置为mod_rewritetrace5

Note

这将替换服务器早期版本中存在的按模块记录的指令,例如RewriteLog

Access Log

Related Modules Related Directives
mod_log_config
mod_setenvif
CustomLog
LogFormat
SetEnvIf

服务器访问日志记录服务器处理的所有请求。访问日志的位置和内容由CustomLog指令控制。 LogFormat指令可用于简化日志内容的选择。本节介绍如何配置服务器以在访问日志中记录信息。

当然,将信息存储在访问日志中只是日志 Management 的开始。下一步是分析此信息以生成有用的统计信息。日志分析通常不在本文档的讨论范围之内,并不是 Web 服务器本身工作的一部分。有关此主题的更多信息以及执行日志分析的应用程序,请检查Open Directory

各种版本的 Apache httpd 使用其他模块和指令来控制访问日志记录,包括 mod_log_referer,mod_log_agent 和TransferLog指令。 CustomLog指令现在包含了所有较旧指令的功能。

访问日志的格式是高度可配置的。使用看起来像 C 样式 printf(1)格式字符串的格式字符串指定格式。下一节将介绍一些示例。有关格式字符串可能内容的完整列表,请参见mod_log_config format strings

通用日志格式

访问日志的典型配置如下所示。

LogFormat "%h %l %u %t \"%r\" %>s %b" common
CustomLog logs/access_log common

这定义昵称 common并将其与特定的日志格式字符串关联。格式字符串由百分比指令组成,每个指令均指示服务器记录特定信息。Literals 字符也可以放在格式字符串中,并将直接复制到日志输出中。引号字符(")必须通过在其前面加上反斜杠进行转义,以防止将其解释为格式字符串的结尾。格式字符串也可以包含特殊控制字符“ \n”(换行)和“ \t”(制表符)。

CustomLog指令使用定义的* nickname *设置新的日志文件。除非以斜杠开头,否则访问日志的文件名是相对于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

下面描述了此日志条目的每个部分。

[day/month/year:hour:minute:second zone] day = 2*digit month = 3*letter year = 4*digit hour = 2*digit minute = 2*digit second = 2*digit zone = (`+' | `-') 4*digit

通过在日志格式字符串中指定%{format}t可以使时间以另一种格式显示,其中format与 C 标准库中的strftime(3)相同,或其中一种受支持的特殊标记。有关详细信息,请参见mod_log_config format strings

合并日志格式

另一种常用的格式字符串称为合并日志格式。可以如下使用。

LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" combined
CustomLog log/access_log combined

此格式与“通用日志格式”完全相同,只是增加了两个字段。每个其他字段都使用百分比指令%{header}i,其中* header *可以是任何 HTTP 请求 Headers。这种格式的访问日志如下所示:

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显示了如何模拟ReferLogAgentLog指令的效果。

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指令定义昵称。而是可以直接在CustomLog指令中指定日志格式。

Conditional Logs

有时根据 Client 端请求的 Feature 方便地从访问日志中排除某些条目是很方便的。借助environment variables可以轻松完成此操作。首先,必须设置环境变量以指示请求满足某些条件。通常使用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,将记录User-agent。在其他情况下,将记录 Literals“-”。同样,在第二个示例中,如果 HTTP 状态代码不是 200、204 或 302,则将记录Referer。(请注意状态代码前的“!”。

尽管我们刚刚显示了条件日志记录非常强大和灵活,但这并不是控制日志内容的唯一方法。日志文件包含服务器活动的完整记录时,它们将更为有用。通常,简单地对日志文件进行后处理以删除您不想考虑的请求通常会更容易。

Log Rotation

即使在繁忙的服务器上,日志文件中存储的信息量也很大。访问日志文件通常每 10,000 个请求增长 1 MB 或更多。因此,有必要通过移动或删除现有日志来定期轮换日志文件。服务器运行时无法完成此操作,因为只要 Apache httpd 保持打开状态,它将 continue 写入旧日志文件。而是,在移动或删除日志文件后,服务器必须为restarted,以便它将打开新的日志文件。

通过使用优美的重新启动,可以指示服务器打开新的日志文件,而不会丢失来自 Client 端的任何现有连接或挂起的连接。但是,为了完成此操作,服务器必须在完成为旧请求的处理时 continue 写入旧日志文件。因此,必须在重新启动后 await 一段时间,然后再对日志文件进行任何处理。简单地旋转日志并压缩旧日志以节省空间的典型方案是:

mv access_log access_log.old mv error_log error_log.old apachectl graceful sleep 600 gzip access_log.old error_log.old

执行日志轮换的另一种方法是使用piped logs,如下一节所述。

Piped Logs

Apache httpd 能够写入错误,并通过管道将日志文件访问另一个进程,而不是直接访问文件。此功能极大地增加了日志记录的灵 Active,而无需在主服务器中添加代码。为了将日志写入管道,只需将文件名替换为管道字符“ |”,后跟可执行文件的名称,该可执行文件应在其标准 Importing 上接受日志条目。服务器启动时,服务器将启动管道日志进程,如果在服务器运行时崩溃,则将重新启动管道日志进程。 (这最后一个功能就是为什么我们可以将此技术称为“可靠的管道记录”.)

父 Apache httpd 进程产生了管道日志进程,并继承了该进程的用户 ID。这意味着管道日志程序通常以 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 过程,并在重新启动期间出现 signal 处理问题。出于与 Apache 2.2 兼容性的考虑,还支持符号“ ||”,等效于使用“ |”。

Windows note

请注意,在 Windows 上,运行许多管道 Logger 进程时可能会遇到问题,尤其是当 HTTPD 作为服务运行时。这是由于桌面堆空间不足而引起的。分配给每个服务的桌面堆空间是由 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SessionManager\SubSystems\Windows 注册表值中SharedSection参数的第三个参数指定的。 请谨慎更改此值 ;更改 Windows 注册表的一般注意事项适用,但是如果将数字调整得太高,您也可能会耗尽桌面堆池。

Virtual Hosts

当运行具有许多virtual hosts的服务器时,有几种处理日志文件的选项。首先,可以完全像在单主机服务器中那样使用日志。只需将日志记录伪指令放在主服务器上下文中<VirtualHost>部分之外,就可以将所有请求记录在同一访问日志和错误日志中。此技术无法轻松收集各个虚拟主机上的统计信息。

如果将CustomLogErrorLog指令放在<VirtualHost>节中,则对该虚拟主机的所有请求或错误将仅记录到指定文件中。任何没有日志记录指令的虚拟主机仍会将其请求发送到主服务器日志。该技术对于少量的虚拟主机非常有用,但是如果主机的数量很大,则 Management 起来可能会很复杂。此外,它经常会与文件 Descriptors 不足产生问题。

对于访问日志,有一个很好的折衷方案。通过将虚拟主机上的信息添加到日志格式字符串中,可以将所有主机记录到同一日志中,然后将日志拆分为单个文件。例如,考虑以下指令。

LogFormat "%v %l %u %t \"%r\" %>s %b" comonvhost
CustomLog logs/access_log comonvhost

%v用于记录正在处理请求的虚拟主机的名称。然后,可以使用诸如split-logfile之类的程序对访问日志进行后处理,以便将其分为每个虚拟主机一个文件。

其他日志文件

Related Modules Related Directives
mod_logio
mod_log_config
mod_log_forensic
mod_cgi
LogFormat
BufferedLogs
ForensicLog
PidFile
ScriptLog
ScriptLogBuffer
ScriptLogLength

记录发送和接收的实际字节

mod_logio添加了两个附加的LogFormat字段(%I 和%O),它们记录了网络上实际接收和发送的字节数。

Forensic Logging

mod_log_forensic提供 Client 请求的取证日志。记录是在处理请求之前和之后完成的,因此取证日志包含每个请求的两条日志行。取证 Logger 非常严格,没有自定义设置。它可以是宝贵的调试和安全工具。

PID File

启动时,Apache httpd 将父 httpd 进程的进程 ID 保存到文件logs/httpd.pid。可以使用PidFile指令更改此文件名。进程 ID 供 Management 员用于通过向父进程发送 signal 来重新启动和终止守护程序。在 Windows 上,请改用-k 命令行选项。有关更多信息,请参见停止并重新启动页。

Script Log

为了帮助调试,使用ScriptLog指令可以记录 CGI 脚本的 Importing 和输出。仅应将其用于测试中,而不应用于实时服务器。 mod_cgi文档中提供了更多信息。

首页