Nginx 访问日志与日志格式

1. 先理解这件事

对新手来说,可以先把访问日志理解成一句话:

  • 它记录了“谁在什么时间访问了什么资源,结果怎么样”

访问日志最直接的用途有三个:

  • 确认请求是否真的到达了 Nginx
  • 观察状态码、响应时间和请求来源
  • 为后续分析流量、排查问题、做告警提供原始数据

对有经验的读者,更值得关注的是:

  • 日志字段是否足够支持排障和性能分析
  • 日志格式是否方便被 ELK、Loki、Datadog 等系统采集
  • 高流量场景下日志 I/O 是否成为额外负担

2. 最小可用配置

http {
    log_format main '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent" '
                    'rt=$request_time uct=$upstream_connect_time '
                    'uht=$upstream_header_time urt=$upstream_response_time';
 
    access_log /var/log/nginx/access.log main;
 
    server {
        listen 80;
        server_name example.com;
 
        location / {
            proxy_pass http://127.0.0.1:3000;
        }
    }
}

先看懂这几行:

  • log_format main ... 定义一套可复用的日志格式
  • access_log /var/log/nginx/access.log main; 表示把访问日志写到指定文件,并套用 main
  • request_timeupstream_response_time 这些字段可以帮助判断慢请求发生在 Nginx 还是上游服务

3. 常见字段怎么理解

最常用字段包括:

  • $remote_addr:客户端来源 IP
  • $time_local:本地时间格式的请求时间
  • $request:原始请求行,通常包含方法、路径和协议版本
  • $status:响应状态码
  • $body_bytes_sent:返回给客户端的响应体大小
  • $http_referer:来源页面
  • $http_user_agent:客户端标识
  • $request_time:Nginx 处理完整个请求所花时间
  • $upstream_response_time:上游服务实际处理时间

新手先把下面三类字段用起来就够了:

  • 访问来源
  • 状态码
  • 耗时

进阶再补:

  • 上游连接耗时
  • 上游响应耗时
  • 转发目标标识

4. 一套更适合排障的日志格式

http {
    log_format upstream_timing '$remote_addr [$time_local] '
                               '"$request" $status $body_bytes_sent '
                               'host=$host uri="$uri" args="$args" '
                               'rt=$request_time '
                               'uaddr=$upstream_addr '
                               'ustatus=$upstream_status '
                               'uct=$upstream_connect_time '
                               'uht=$upstream_header_time '
                               'urt=$upstream_response_time';
 
    access_log /var/log/nginx/access.log upstream_timing;
}

这套格式的价值在于:

  • 能分辨慢请求到底慢在客户端传输、Nginx 本身还是上游服务
  • 能看见请求最终被转发到了哪个上游地址
  • 能为后续做性能优化和故障定位留足上下文

5. 配置时的实践建议

  1. 日志格式先满足排障,再考虑精简。
  2. 字段命名尽量稳定,避免后续日志平台解析规则反复调整。
  3. 高并发场景要评估日志量,必要时配合日志切分和采集系统使用。
  4. 对健康检查、静态资源等高频低价值请求,可以考虑单独日志策略。

6. 常见误区

6.1 只记录默认格式,后面排障信息不够

这是最常见的问题。

默认格式能看基础状态,但很多线上问题真正需要的是:

  • 请求耗时
  • 上游耗时
  • 上游状态
  • 具体转发目标

6.2 字段加得太多,日志量暴涨

日志不是字段越多越好,而是要围绕分析目标设计。

更合理的做法是:

  • 核心访问日志保留稳定字段
  • 特殊场景单独定义更详细的格式

7. 排查清单

  • access_log 已明确写到预期位置
  • log_format 命名清晰且已被实际引用
  • 已记录状态码、请求耗时、上游耗时等关键字段
  • 日志目录权限正确,Nginx 可正常写入
  • 已配合日志切分或采集方案,避免单文件无限增长

8. 相关笔记