Nginx 日志完全指南:access_log/error_log 配置、JSON 结构化与条件记录
Nginx 访问日志和错误日志在哪、怎么配?本文详解 log_format 自定义格式、escape=json 输出结构化日志、按状态码的条件日志、error_log 级别控制与 Docker 环境下的日志采集,并给出接入观测云实现集中检索与告警的落地路径。
Nginx 日志(Nginx Logging)由访问日志(access log)与错误日志(error log)组成:访问日志逐条记录客户端请求的处理结果,错误日志记录请求处理及服务运行中的异常事件。 作为使用率最高的 Web 服务器与反向代理之一,把 Nginx 日志配置好、结构化好,是 Web 可观测的第一步。
核心要点速览
- 默认位置
/var/log/nginx/access.log与error.log;Docker 官方镜像把二者软链到 stdout/stderr; - 访问日志默认 combined 格式,用
log_format可自定义,加escape=json可直接输出 JSON; - 高流量下用
map+if=做条件日志,只记 4xx/5xx 或按采样记录,显著降噪降本; error_log第二参数控制级别(默认 error,Docker 镜像默认 notice);- 集中采集后,先检查时间、HTTP 状态码与日志级别字段,再按服务和状态码建立查询。
日志文件在哪里?
Linux 直装场景默认在 /var/log/nginx/ 目录。找不到时用 sudo nginx -t 定位配置文件,再查其中的 error_log 与 access_log 指令。
Docker 场景:官方镜像将 /var/log/nginx/access.log 软链到 /dev/stdout、error.log 软链到 /dev/stderr,所以直接用 docker logs -f <容器> 查看;只看访问日志加 2>/dev/null,只看错误日志加 1>/dev/null。
访问日志:默认格式解读
默认 combined 格式:
'$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"'
对应一条日志逐字段解读:
| 字段 | 示例 | 含义 |
|---|---|---|
$remote_addr |
172.17.0.1 | 客户端 IP |
$time_local |
[27/May/2026:16:37:59 +0000] | 本地时间 |
$request |
"GET / HTTP/1.1" | 方法、URI、协议 |
$status |
200 | 响应状态码 |
$body_bytes_sent |
615 | 响应体字节数 |
$http_referer |
"-" | 来源页 |
$http_user_agent |
Mozilla/5.0 ... | 客户端 UA |
$http_x_forwarded_for |
"-" | 经过代理时的原始客户端 IP |
自定义格式与 JSON 结构化
在 http 块中用 log_format 定义、在 access_log 中按名启用。例如加上 $host 记录域名:
log_format with_host '$remote_addr - [$time_local] "$host" "$request" $status $body_bytes_sent "$http_user_agent"';
access_log /var/log/nginx/access.log with_host;
更进一步,直接输出 JSON——这是接入日志平台的最佳姿势:
log_format json_access escape=json '{'
'"time":"$time_iso8601",'
'"remote_ip":"$remote_addr",'
'"method":"$request_method",'
'"uri":"$request_uri",'
'"status":$status,'
'"bytes_sent":$bytes_sent,'
'"duration_sec":$request_time,'
'"user_agent":"$http_user_agent",'
'"trace_id":"$http_x_request_id"'
'}';
access_log /var/log/nginx/access.log json_access;
escape=json 会转义变量值中的引号等字符,整体 JSON 结构仍取决于 log_format 的写法。要在观测云关联日志与链路,日志中的 trace_id 必须与探针生成的链路标识一致;普通 X-Request-Id 不能直接当作这个标识,需按日志关联配置完成注入。
高流量降噪:条件日志
通过 map 定义"是否记录"的开关,跳过 2xx/3xx 只留异常:
map $status $loggable {
~^[23] 0;
default 1;
}
access_log /var/log/nginx/access.log combined if=$loggable;
典型用法:只记 4xx/5xx、排除已知爬虫 UA、只对特定路径记录。若应用层已记录完整请求日志,也可用 access_log off; 彻底关闭 Nginx 访问日志。
错误日志:级别与多文件
error_log /var/log/nginx/error.log warn;
级别从低到高:debug → info → notice → warn → error → crit → alert → emerg。未配置时默认记录 error 及以上(官方 Docker 镜像默认为 notice)。错误日志格式固定为"时间 [级别] pid#tid: *cid 消息, client/ server/ request 上下文",不支持自定义格式,但支持多文件分级输出:
error_log /var/log/nginx/error.log info;
error_log /var/log/nginx/emerg.log emerg;
接入观测云:从采集到告警
在 DataKit 的 Nginx 采集器中,将日志配置的 files 指向访问日志和错误日志路径,并指定 nginx.p 解析脚本。官方示例分别说明了两类日志的提取字段,其中 status_code 表示 HTTP 状态码,status 表示日志级别 。
容器使用 stdout/stderr 输出时,按容器运行时的日志路径配置采集。自定义 JSON 格式则需要匹配的 Pipeline 脚本;先用样例检查 time、状态码和 URI,再统计 5xx 数量,设置检测窗口、阈值与通知对象 。
总结
Nginx 日志配置的三板斧:access 侧用 log_format + escape=json 走向结构化,用 map 条件日志控制体量;error 侧用级别控制详略。集中采集后,保留原始日志与解析字段,方便从状态码统计回到具体请求。
常见问题(FAQ)
Q:access.log 里的 $request_time 和 $upstream_response_time 有什么区别?
$request_time 是 Nginx 处理请求的完整耗时(含读写客户端);$upstream_response_time 只是上游后端响应的耗时。反向代理场景下二者差值大,通常说明慢在客户端网络或 Nginx 缓冲。
Q:为什么配置了 log_format 却不生效?
log_format 只是"定义",必须在 access_log 指令中按名字引用才生效;另外自定义格式只能写在 http 块中,写到 server 块会报语法错误。
Q:Docker 里想把 Nginx 日志同时落盘怎么办?
可在 nginx.conf 中额外添加一条指向挂载目录的 access_log /var/log/nginx/file_access.log;(Nginx 支持多目标同时输出),或将宿主机目录挂载进容器再按文件采集。
Q:观测云能直接解析 combined 文本格式吗?
可以使用 Nginx 采集器提供的 Pipeline 示例解析常见访问日志。自定义字段或格式与示例不同时,需要调整脚本并用样例验证;JSON 输出也需要正确配置字段提取。
系列阅读:Apache 日志详解 | 微服务日志最佳实践