要让Nginx日志真实反映客户端行为与性能瓶颈,必须精准注入真实IP和分层耗时:启用realip模块并配置可信代理网段与头字段以获取$realip_remote_addr;同时记录$request_time与$upstream_response_time以定位Nginx层或后端瓶颈;推荐使用结构化JSON格式log_format,含UTC时间、完整URI、数值无引号等规范,并通过access_log显式启用。

要让 Nginx 日志真正反映真实客户端行为和系统性能瓶颈,关键不是简单拼几个变量,而是精准注入真实 IP和分层耗时这两个核心维度。这需要两步配合:一是用对变量,二是配好前置模块。
必须启用 realip 模块才能拿到真实 IP
仅靠 $remote_addr 在有 CDN、LB 或反向代理时,记录的只是上一跳地址(比如 10.0.1.5),不是用户真实 IP。必须启用 ngx_http_realip_module 并配置可信代理网段:
- 在 http 块中添加:
set_real_ip_from 10.0.0.0/8;(替换成你实际的 LB/CDN 网段) - 指定信任的头字段:
real_ip_header X-Forwarded-For;(或 X-Real-IP) - 之后才能安全使用
$realip_remote_addr—— 这才是经校验后的最终客户端 IP - 同时保留
$http_x_forwarded_for字段,用于查看完整代理链(如203.0.113.42, 192.0.2.10)
耗时必须拆开看:request_time vs upstream_response_time
单个“总耗时”无法定位瓶颈。Nginx 提供两个独立变量,必须同时记录:
-
$request_time:从接收到请求第一个字节,到发送完响应最后一个字节的总时间(单位:秒,精度毫秒,如 0.047) -
$upstream_response_time:后端服务返回第一个字节所用时间(多个 upstream 会以逗号分隔,如0.021, 0.018) - 二者差值 ≈ Nginx 自身处理开销(解析、重写、SSL、日志等),若该值突增,说明问题在 Nginx 层而非后端
推荐的生产级 log_format 示例(含真实 IP 与双耗时)
以下格式已兼顾可读性、结构化和审计要求,可直接放入 http 块:
log_format audit '{"time":"$time_iso8601","client":"$realip_remote_addr","xff":"$http_x_forwarded_for","method":"$request_method","uri":"$request_uri","status":$status,"size":$body_bytes_sent,"rt":$request_time,"urt":"$upstream_response_time","ua":"$http_user_agent","referer":"$http_referer"}';- 使用
$time_iso8601而非$time_local,确保所有节点时间戳统一为 UTC,便于集中分析 -
$request_uri保留完整 query string(如/api/login?user=admin&pwd=123),审计路径类攻击必需 - 数值字段(status、size、rt)不加引号,JSON 解析器可直接识别为数字类型;字符串字段全用双引号包裹
- 字段名全小写+下划线,避免空格和特殊符号,兼容 Elasticsearch / Loki / Grafana 的自动 schema 推断
别忘了绑定 access_log 才生效
定义完 log_format 后,必须在 server 或 location 块中显式启用:
access_log /var/log/nginx/access-audit.log audit buffer=64k flush=5s;- 加
buffer和flush可显著降低磁盘 I/O,尤其高并发场景 - 审计日志建议单独路径,避免和默认日志混在一起,也方便权限隔离与日志轮转策略


















