# 日志文件
要有效地管理Web服务器,就有必要反馈服务器的活动、性能以及出现的问题。Apache HTTP服务器提供了非常全面而灵活的日志记录功能。本文将阐述如何配置文件以及如何理解日志内容。
## 安全警告
任何人只要对Apache存放日志文件的目录具有写权限,也就当然地可以获得启动Apache的用户(通常是root)的权限,_绝对不要_随意给予任何人存放日志文件目录的写权限。细节请参见[安全方面的提示](#calibre_link-263)。
另外,日志文件可能会包含未加转换的来自用户的信息,用户就有机会恶意插入控制符,所以处理原始日志时应该当心这个问题。
## 错误日志(Error Log)
相关模块
* `ErrorLog`
* `LogLevel`
相关指令
错误日志是最重要的日志文件,其文件名和位置取决于`ErrorLog`指令。Apache httpd将在这个文件中存放诊断信息和处理请求中出现的错误,由于这里经常包含了出错细节以及如何解决,如果服务器启动或运行中有问题,首先就应该查看这个错误日志。
错误日志通常被写入一个文件(unix系统上一般是`error_log` ,Windows和OS/2上一般是`error.log`)。在unix系统中,错误日志还可能被重定向到`syslog`或[通过管道操作传递给一个程序](#calibre_link-491)。
错误日志的格式相对灵活,并可以附加文字描述。某些信息会出现在绝大多数记录中,一个典型的例子是:
```
[Wed Oct 11 14:32:52 2000] [error] [client 127.0.0.1]
client denied by server configuration:
/export/home/live/ap/htdocs/test
```
其中,第一项是错误发生的日期和时间;第二项是错误的严重性,`LogLevel`指令使只有高于指定严重性级别的错误才会被记录;第三项是导致错误的IP地址;此后是信息本身,在此例中,服务器拒绝了这个客户的访问。服务器在记录被访问文件时,用的是文件系统路径,而不是Web路径。
错误日志中会包含类似上述例子的多种类型的信息。此外,CGI脚本中任何输出到`stderr`的信息会作为调试信息原封不动地记录到错误日志中。
用户可以增加或删除错误日志的项。但是对某些特殊请求,在[访问日志(access log)](#calibre_link-492)中也会有相应的记录,比如上述例子在访问日志中也会有相应的记录,其状态码是403,因为访问日志也可以定制,所以可以从访问日志中得到错误事件的更多信息。
在测试中,对任何问题持续监视错误日志是非常有用的。在unix系统中,可以这样做:
```
tail -f error_log
```
## 访问日志(Access Log)
相关模块
* `mod_log_config`
* `mod_setenvif`
相关指令
* `CustomLog`
* `LogFormat`
* `SetEnvIf`
访问日志中会记录服务器所处理的所有请求,其文件名和位置取决于`CustomLog`指令,`LogFormat`指令可以简化日志的内容。这里阐述如何配置服务器的访问日志。
实施日志管理,首先当然必须产生访问日志,然后才能分析日志从而得到有用的统计信息。日志分析不是Web服务器的职责,已超出本文的范畴,更多资料和有关分析工具的信息,可以查看[Open Directory](http://dmoz.org/Computers/Software/Internet/Site_Management/Log_analysis/)或[Yahoo](http://dir.yahoo.com/Computers_and_Internet/Software/Internet/World_Wide_Web/Servers/Log_Analysis_Tools/) 。
不同版本的Apache httpd使用了不同的模块和指令来控制对访问的记录,包括mod_log_referer, mod_log_agent和`TransferLog`指令。现在,`CustomLog`指令包含了旧版本中相关指令的所有功能。
访问日志的格式是高度灵活的,使用很象C风格的printf()函数的格式字符串。下面有几个例子,完整的说明可以查看用于`mod_log_config`模块的[格式字符串](#calibre_link-72)。
### 通用日志格式(Common Log Format)
这是一个典型的记录格式:
```
LogFormat "%h %l %u %t \"%r\" %>s %b" common
CustomLog logs/access_log common
```
它定义了一种特定的记录格式字符串,并给它起了个_别名_叫`common` ,其中的"%"指示服务器用某种信息替换,其他字符则不作替换。引号(`"`)必须加反斜杠转义,以避免被解释为字符串的结束。格式字符串还可以包含特殊的控制符,如换行符"`\n`" 、制表符"`\t`"。
`CustomLog`指令建立一个使用指定_别名_的新日志文件,除非其文件名是以斜杠开头的绝对路径,否则其路径就是相对于`ServerRoot`的相对路径。
上述配置是一种被称为通用日志格式(CLF)的记录格式,它被许多不同的Web服务器所采用,并被许多日志分析程序所识别,它产生的记录形如:
```
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`)
这是发送请求到服务器的客户的IP地址。如果`HostnameLookups`设为 `On` ,则服务器会尝试解析这个IP地址的主机名并替换此处的IP地址,但并不推荐这样做,因为它会显著拖慢服务器,最好是用一个日志后续处理器来判断主机名,比如`logresolve` 。如果客户和服务器之间存在代理,那么记录中的这个IP地址就是那个代理的IP地址,而不是客户机的真实IP地址。
`-` (`%l`)
这是由客户端`identd`进程判断的RFC1413身份(identity),输出中的符号"-"表示此处的信息无效。除非在严格控制的内部网络中,此信息通常很不可靠,不应该被使用。只有在将`IdentityCheck`指令设为 `On` 时,Apache才会试图得到这项信息。
`frank` (`%u`)
这是HTTP认证系统得到的访问该网页的客户标识(userid),环境变量`REMOTE_USER`会被设为该值并提供给CGI脚本。如果状态码是401,表示客户未通过认证,则此值没有意义。如果网页没有设置密码保护,则此项将是"`-`"。
`[10/Oct/2000:13:55:36 -0700]` (`%t`)
这是服务器完成请求处理时的时间,其格式是:
`[日/月/年:时:分:秒 时区]
日 = 2数字
月 = 3字母
年 = 4数字
时 = 2数字
分 = 2数字
秒 = 2数字
时区 = (+|-)4数字`
可以在格式字符串中使用 `%{format}t` 来改变时间的输出形式,其中的`format`与C标准库中的`strftime()`用法相同。
`"GET /apache_pb.gif HTTP/1.0"` (`\"%r\"`)
引号中是客户端发出的包含许多有用信息的请求行。可以看出,该客户的动作是`GET` ,请求的资源是`/apache_pb.gif` ,使用的协议是`HTTP/1.0` 。另外,还可以记录其他信息,如:格式字符串"`%m %U%q %H`"会记录动作、路径、查询字符串、协议,其输出和"`%r`"一样。
`200` (`%>s`)
这是服务器返回给客户端的状态码。这个信息非常有价值,因为它指示了请求的结果,或者是被成功响应了(以2开头),或者被重定向了(以3开头),或者出错了(以4开头),或者产生了服务器端错误(以5开头)。完整的状态码列表参见[HTTP规范](http://www.w3.org/Protocols/rfc2616/rfc2616.txt)(RFC2616第10章)。
`2326` (`%b`)
最后这项是返回给客户端的不包括响应头的字节数。如果没有信息返回,则此项应该是"`-`",如果希望记录为"`0`"的形式,就应该用`%B` 。
### 组合日志格式(Combined Log Format)
另一种常用的记录格式是组合日志格式,形式如下:
```
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\"
\"%{User-agent}i\"" combined
CustomLog log/access_log combined
```
这种格式与通用日志格式类似,但是多了两个 `%{_header_}i` 项,其中的_header_可以是任何请求头。这种格式的记录形如:
```
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\"`)
"Referer"请求头。此项指明了该请求是被从哪个网页提交过来的,这个网页应该包含有`/apache_pb.gif`或者其连接。
`"Mozilla/4.08 [en] (Win98; I ;Nav)"` (`\"%{User-agent}i\"`)
"User-Agent"请求头。此项是客户端提供的浏览器识别信息。
### 多文件访问日志
可以简单地在配置文件中用多个`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"
```
此例也说明了,记录格式可以直接由`CustomLog`指定,而并不一定要用`LogFormat`起一个别名。
### 条件日志
许多时候,根据与请求特征相关的[环境变量](#calibre_link-232)来有选择地记录某些客户端请求会带来便利。首先,需要使用`SetEnvIf`指令来设置特定的[环境变量](#calibre_link-232)以标识符合某种特定条件的请求,然后用`CustomLog`指令的 `env=` 子句,根据这些[环境变量](#calibre_link-232)来决定记录或排除特定的请求。例如:
```
# 不记录本机发出的请求
SetEnvIf Remote_Addr "127\.0\.0\.1" dontlog
# 不记录对robots.txt文件的请求
SetEnvIf Request_URI "^/robots\.txt$" dontlog
# 记录其他请求
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
```
虽然上述已经展示了条件日志记录的强大和灵活,但这不是控制日志内容的唯一手段,还可以用日志后继处理程序来剔除你不关心的内容,从而使日志更加有用。
## 日志滚动
即使一个并不繁忙的服务器,其日志文件的信息量也会很大,一般每10000个请求,访问日志就会增加1MB或更多。这就有必要定期滚动日志文件。由于Apache会保持日志文件的打开,并持续写入信息,因此服务器运行期间不能执行滚动操作。移动或者删除日志文件以后,必须[重新启动](#calibre_link-31)服务器才能让它打开新的日志文件。
用_优雅的(graceful)_方法重新启动,可以使服务器启用新的日志文件,而不丢失原来尚未写入的信息。为此,有必要等待一段时间,让服务器完成正在处理的请求,并将记录写入到原来的日志文件。以下是一个典型的日志滚动和为节省存储空间而压缩旧日志的例子:
```
mv access_log access_log.old
mv error_log error_log.old
apachectl graceful
sleep 600
gzip access_log.old error_log.old
```
另一种执行滚动的方法是使用下一节阐述的[管道日志](#calibre_link-491)。
## 管道日志
Apache httpd可以通过管道将访问记录和出错信息传递给另一个进程,而不是写入一个文件,由于无须对主服务器进行编程,这个功能显著地增强了日志的灵活性。只要用管道操作符"`|`"后面跟一个可执行文件名,就可以使这个程序从标准输入设备获得事件记录。Apache在启动时,会同时启动这个管道日志进程,并且在运行过程中,如果这个进程崩溃了,会重新启动这个进程(所以我们称这个技术为"可靠管道日志")。
管道日志进程由其父进程Apache httpd产生,并继承其权限,这意味着管道进程通常是作为root运行的,所以保持这个程序简单而安全极为重要。
管道日志的一种重要用途是,允许日志滚动而无须重新启动服务器。为此,服务器提供了一个简单的程序`rotatelogs` 。每24小时滚动一次日志的例子如下:
```
CustomLog "|/usr/local/apache/bin/rotatelogs /var/log/access_log 86400" common
```
注意:引号用于界定整个管道命令行。虽然这是针对访问日志的,但是其用法对于其他日志也一样。
在其他站点,有一个类似但更灵活的日志滚动程序叫[cronolog](http://www.cronolog.org/) 。
如果有较简单的离线处理日志的方案,就不应该使用条件日志和管道日志,即使它们非常强大。
## 虚拟主机
如果服务器配有若干[虚拟主机](#calibre_link-36),那么还有几个控制日志文件的功能。首先,可以把日志指令放在`<VirtualHost>`段之外,让它们与主服务器使用同一个访问日志和错误日志来记录所有的请求和错误,但是这样就不能方便的获得每个虚拟主机的信息了。
如果把`CustomLog`或`ErrorLog`指令放在`<VirtualHost>`段内,所有对这个虚拟主机的请求和错误信息会被记录在其私有的日志文件中,那些没有在`<VirtualHost>`段内使用日志指令的虚拟主机将仍然和主服务器使用同一个日志。这种方法对虚拟主机较少的服务器很有用,但虚拟主机非常多时,就会带来管理上的困难,还经常会产生[文件描述符短缺](#calibre_link-68)的问题。
对于访问日志,有一个很好的折衷方案,在同一个访问日志文件中记录对所有主机的访问,而每条记录都注明虚拟主机的信息,日后再把记录拆开存入不同的文件。例如:
```
LogFormat "%v %l %u %t \"%r\" %>s %b" comonvhost
CustomLog logs/access_log comonvhost
```
`%v` 用来附加虚拟主机的信息。有个[split-logfile](#calibre_link-73)程序可以根据不同的虚拟主机信息对日志进行拆分,并将结果存入不同的文件。
## 其他日志文件
相关模块
* `mod_logio`
* `mod_log_forensic`
* `mod_cgi`
* `mod_rewrite`
相关指令
* `LogFormat`
* `ForensicLog`
* `PidFile`
* `RewriteLog`
* `RewriteLogLevel`
* `ScriptLog`
* `ScriptLogBuffer`
* `ScriptLogLength`
### 记录接收和发送的实际字节数
`mod_logio`增加了两个额外的`LogFormat`字段(%I 和 %O)用于记录接收和发送的实际字节数。
### 对比记录(Forensic Logging)
`mod_log_forensic`提供了对客户端请求的_对比_记录,也就是在请求被处理之前和处理完成之后进行两次记录,所以对比日志(forensic log)对于每个请求都包含两条记录。对比记录器(forensic logger)十分严格,不可以进行定制。它可以成为无价的调试和安全工具。
### PID文件
在启动时,Apache httpd将会在`logs/httpd.pid`文件中保存其父进程httpd的进程ID(process id[PID])。该文件名可以用`PidFile`指令改变。该PID可以被管理员利用来重新启动或者终止服务器后台守护进程。在Windows中,可以使用命令行参数 -k 。更多信息请参见[停止和重新启动](#calibre_link-31)。
### 脚本日志
为了方便调试,可以用`ScriptLog`指令来记录CGI脚本的输入和输出。此功能应该仅用于测试,而不应该用于正常工作的服务器。更多资料请参见[mod_cgi](#calibre_link-218)文档。
### 重写日志
在使用强大且灵活的[mod_rewrite](#calibre_link-34)时,几乎都有必要用`RewriteLog`来帮助调试。这个日志提供了重写引擎如何转换请求的详细分解信息,其详细程度取决于`RewriteLogLevel`指令。
- Apache HTTP Server Version 2.2 文档 [最后更新:2006年3月21日]
- 版本说明
- 从1.3升级到2.0
- 从2.0升级到2.2
- Apache 2.2 新特性概述
- Apache 2.0 新特性概述
- The Apache License, Version 2.0
- 参考手册
- 编译与安装
- 启动Apache
- 停止和重启
- 配置文件
- 配置段(容器)
- 缓冲指南
- 服务器全局配置
- 日志文件
- 从URL到文件系统的映射
- 安全方面的提示
- 动态共享对象(DSO)支持
- 内容协商
- 自定义错误响应
- 地址和端口的绑定(Binding)
- 多路处理模块
- Apache的环境变量
- Apache处理器的使用
- 过滤器(Filter)
- suEXEC支持
- 性能方面的提示
- URL重写指南
- Apache虚拟主机文档
- 基于主机名的虚拟主机
- 基于IP地址的虚拟主机
- 大批量虚拟主机的动态配置
- 虚拟主机示例
- 深入研究虚拟主机的匹配
- 文件描述符限制
- 关于DNS和Apache
- 常见问题
- 经常问到的问题
- Apache的SSL/TLS加密
- SSL/TLS高强度加密:绪论
- SSL/TLS高强度加密:兼容性
- SSL/TLS高强度加密:如何...?
- SSL/TLS Strong Encryption: FAQ
- 如何.../指南
- 认证、授权、访问控制
- CGI动态页面
- 服务器端包含入门
- .htaccess文件
- 用户网站目录
- 针对特定平台的说明
- 在Microsoft Windows中使用Apache
- 在Microsoft Windows上编译Apache
- Using Apache With Novell NetWare
- Running a High-Performance Web Server on HPUX
- The Apache EBCDIC Port
- 服务器和支持程序
- httpd - Apache超文本传输协议服务器
- ab - Apache HTTP服务器性能测试工具
- apachectl - Apache HTTP服务器控制接口
- apxs - Apache 扩展工具
- configure - 配置源代码树
- dbmmanage - 管理DBM格式的用户认证文件
- htcacheclean - 清理磁盘缓冲区
- htdbm - 操作DBM密码数据库
- htdigest - 管理用于摘要认证的用户文件
- httxt2dbm - 生成RewriteMap指令使用的dbm文件
- htpasswd - 管理用于基本认证的用户文件
- logresolve - 解析Apache日志中的IP地址为主机名
- rotatelogs - 滚动Apache日志的管道日志程序
- suexec - 在执行外部程序之前切换用户
- 其他程序
- 杂项文档
- 与Apache相关的标准
- Apache模块
- 描述模块的术语
- 描述指令的术语
- Apache核心(Core)特性
- Apache MPM 公共指令
- Apache MPM beos
- Apache MPM event
- Apache MPM netware
- Apache MPM os2
- Apache MPM prefork
- Apache MPM winnt
- Apache MPM worker
- Apache模块 mod_actions
- Apache模块 mod_alias
- Apache模块 mod_asis
- Apache模块 mod_auth_basic
- Apache模块 mod_auth_digest
- Apache模块 mod_authn_alias
- Apache模块 mod_authn_anon
- Apache模块 mod_authn_dbd
- Apache模块 mod_authn_dbm
- Apache模块 mod_authn_default
- Apache模块 mod_authn_file
- Apache模块 mod_authnz_ldap
- Apache模块 mod_authz_dbm
- Apache模块 mod_authz_default
- Apache模块 mod_authz_groupfile
- Apache模块 mod_authz_host
- Apache模块 mod_authz_owner
- Apache模块 mod_authz_user
- Apache模块 mod_autoindex
- Apache模块 mod_cache
- Apache模块 mod_cern_meta
- Apache模块 mod_cgi
- Apache模块 mod_cgid
- Apache模块 mod_charset_lite
- Apache模块 mod_dav
- Apache模块 mod_dav_fs
- Apache模块 mod_dav_lock
- Apache模块 mod_dbd
- Apache模块 mod_deflate
- Apache模块 mod_dir
- Apache模块 mod_disk_cache
- Apache模块 mod_dumpio
- Apache模块 mod_echo
- Apache模块 mod_env
- Apache模块 mod_example
- Apache模块 mod_expires
- Apache模块 mod_ext_filter
- Apache模块 mod_file_cache
- Apache模块 mod_filter
- Apache模块 mod_headers
- Apache模块 mod_ident
- Apache模块 mod_imagemap
- Apache模块 mod_include
- Apache模块 mod_info
- Apache模块 mod_isapi
- Apache模块 mod_ldap
- Apache模块 mod_log_config
- Apache模块 mod_log_forensic
- Apache模块 mod_logio
- Apache模块 mod_mem_cache
- Apache模块 mod_mime
- Apache模块 mod_mime_magic
- Apache模块 mod_negotiation
- Apache模块 mod_nw_ssl
- Apache模块 mod_proxy
- Apache模块 mod_proxy_ajp
- Apache模块 mod_proxy_balancer
- Apache模块 mod_proxy_connect
- Apache模块 mod_proxy_ftp
- Apache模块 mod_proxy_http
- Apache模块 mod_rewrite
- Apache模块 mod_setenvif
- Apache模块 mod_so
- Apache模块 mod_speling
- Apache模块 mod_ssl
- Apache模块 mod_status
- Apache模块 mod_suexec
- Apache模块 mod_unique_id
- Apache模块 mod_userdir
- Apache模块 mod_usertrack
- Apache模块 mod_version
- Apache模块 mod_vhost_alias
- Developer Documentation for Apache 2.0
- Apache 1.3 API notes
- Debugging Memory Allocation in APR
- Documenting Apache 2.0
- Apache 2.0 Hook Functions
- Converting Modules from Apache 1.3 to Apache 2.0
- Request Processing in Apache 2.0
- How filters work in Apache 2.0
- Apache 2.0 Thread Safety Issues
- 词汇和索引
- 词汇表
- 指令索引
- 指令速查
- 模块索引
- 站点导航