Apache 访问日志与错误日志详解:位置、格式解读与自定义配置
Apache 的 access.log 和 error.log 各记录什么?Common/Combined 日志格式每个字段什么含义?本文讲解 Apache 日志的默认位置、格式解读、LogFormat 自定义、JSON 结构化与 LogLevel 级别配置,并给出接入观测云实现统一检索与 5xx 告警的实践路径。
Apache 日志是 Apache HTTP Server 记录自身运行状态的文本文件,分为访问日志(Access Log)与错误日志(Error Log)两类:前者按配置和过滤条件记录请求处理结果,后者记录请求处理中的错误与诊断信息。 作为至今仍承载大量网站流量的老牌 Web 服务器,读懂这两份日志是排查 Apache 问题的起点。
核心要点速览
- 访问日志按配置记录请求(IP、路径、状态码、字节数),错误日志记"出了什么问题"(模块、级别、错误详情);
- Debian/Ubuntu 默认位置是
/var/log/apache2/,RHEL/CentOS 是/var/log/httpd/; - 访问日志格式由
LogFormat定义、CustomLog启用,可输出经验证的 JSON 以便机器解析; - 错误日志用
ErrorLogFormat控制格式、LogLevel控制详略,生产默认warn; - 多站点、多服务器需要统一采集路径、站点标识和字段类型,才能比较各实例的错误分布。
两类日志分别在哪里?
| 系统 | 访问日志 | 错误日志 |
|---|---|---|
| Debian / Ubuntu | /var/log/apache2/access.log |
/var/log/apache2/error.log |
| RHEL / CentOS / Fedora | /var/log/httpd/access_log |
/var/log/httpd/error_log |
查看实时流量用 sudo tail -f /var/log/apache2/access.log;按关键词过滤用 grep(如 sudo grep " 500 " access.log 捞 500 错误)。
访问日志格式解读:每个字段是什么?
格式由主配置中的 LogFormat 指令定义。两种预定义格式:
Common Log Format(通用格式):
LogFormat "%h %l %u %t \"%r\" %>s %b" common
一条典型记录及各字段含义:
127.0.0.1 - - [06/Jun/2026:11:26:42 +0800] "GET /index.html HTTP/1.1" 200 3477
| 占位符 | 示例值 | 含义 |
|---|---|---|
%h |
127.0.0.1 | 远程主机名或 IP(受 HostnameLookups、代理及 mod_remoteip 配置影响) |
%l / %u |
- | 远程登录名 / 认证用户名(无则为 -) |
%t |
[06/Jun/2026:11:26:42 +0800] | 请求时间 |
%r |
"GET /index.html HTTP/1.1" | 方法、路径、协议 |
%>s |
200 | 最终响应状态码 |
%b |
3477 | 响应正文大小,不含响应头;无正文时为 - |
Combined Log Format 在 Common 基础上追加 %{Referer}i(来源页)与 %{User-Agent}i(客户端 UA),是多数发行版的默认格式。
如何自定义与启用格式?
在 apache2.conf 中定义一个含响应耗时的自定义格式:
LogFormat "%t %H %m %U %q %I %>s %O %{ms}T" custom
其中 %I、%O 需要加载 mod_logio,分别包含收到和发出的 HTTP 头字节。
再到虚拟主机配置(如 sites-available/000-default.conf)中启用,检查语法后重新加载:
CustomLog ${APACHE_LOG_DIR}/access.log custom
sudo apachectl configtest && sudo systemctl reload apache2
推荐做法:直接输出 JSON 结构化日志
Apache 对任意字符串的日志转义不保证符合 JSON(可能产生 \xHH)。下面只输出数值字段;需要 URI、UA 等文本时,保留 common/combined 格式并用采集器解析、编码为 JSON:
LogFormat "{ \"status\":%>s, \"body_bytes\":%B, \"duration_ms\":%{ms}T }" json
CustomLog ${APACHE_LOG_DIR}/access.log json
使用样本检查输出能否被 JSON 解析器读取,尤其要覆盖带引号和反斜杠的请求。接入日志平台时仍需配置字段提取和时间解析,不能把 JSON 格式等同于免配置采集 [1]。
错误日志怎么配?
ErrorLog ${APACHE_LOG_DIR}/error.log
ErrorLogFormat "[%{u}t] [%l] [pid %P:tid %T] [client %a] %M"
LogLevel warn
LogLevel 从低到高为 trace8 → … → trace1 → debug → info → notice → warn → error → crit → alert → emerg,指定某级即包含更高严重级;不配置时默认 warn。LogLevel 控制错误日志,不决定访问日志是否记录。排障期可临时调到 debug,完事记得调回,避免刷爆磁盘。
多台 Apache 服务器如何统一分析?
在各服务器安装 DataKit 后,按日志采集配置设置文件路径、source 和 service;访问日志与错误日志格式不同,应分别配置解析规则。用 Pipeline 的 json() 或 grok 提取时间、路径、HTTP 状态码和耗时,再发送测试请求,核对日志查看器中的字段值。
HTTP 状态码建议保存在 http_status_code 等独立字段,日志级别才映射到观测云标准字段 status。确认 500 请求可被检索后,再基于该字段统计 5xx 数量并设置告警阈值;不要用日志级别字段直接比较 HTTP 数值。
总结
Apache 日志体系的核心就两件事:访问日志用 LogFormat 管住"记什么"(JSON 输出须验证转义),错误日志用 LogLevel 管住"记多细"。多主机分析前,先验证时间、站点、状态码与耗时字段是否一致。
常见问题(FAQ)
Q:access.log 里的状态码应该以哪个为准,%s 还是 %>s?
以 %>s 为准。%s 记录的是内部第一次响应的状态,请求经过内部重定向后会失真;%>s 才是返回给客户端的最终状态码。
Q:如何让同一台服务器的不同虚拟主机分开记日志?
在每个 VirtualHost 块内单独配置 CustomLog 和 ErrorLog 指向不同文件即可。虚拟主机自定义 CustomLog 后通常不继承主服务器的 CustomLog;多个同时适用的日志指令或 GlobalLog 才可能重复记录。
Q:错误日志里 [client x.x.x.x] 后面的错误信息看不懂怎么办?
错误日志格式为"时间 [模块:级别] [pid/tid] [客户端] 消息",消息中的 AH 开头编号是 Apache 官方错误码,可结合模块名、完整消息和上下文检索;不是每个编号都有专门的文档页。
Q:改成 JSON 格式后,观测云还需要 Pipeline 吗?
需要按实际采集配置确认。可使用 Pipeline 的 json() 提取字段,再解析时间和映射日志级别;common/combined 文本格式可用 grok。两种格式都应先用真实样本验证。
系列阅读:Nginx 日志完全指南 | Caddy 日志配置指南
[1]: 观测云文档《Pipeline 快速开始》https://docs.guance.com/pipeline/use-pipeline/pipeline-quick-start/