Nginx日志格式定制:如何记录更有价值的访问信息?

Nginx日志格式定制:如何记录更有价值的访问信息?

你的Nginx日志长这样:192.168.1.1 - - [27/Jul/2026:14:30:25 +0800] "GET /index.html HTTP/1.1" 200 15234。这是默认的combined格式,记录了IP、时间、请求方法、状态码、响应大小。看起来够用了。直到你想知道“这个请求到底花了多长时间”,或者“用户真实IP是什么”。默认日志回答不了这些问题。你需要的字段不在里面,因为默认的日志格式没有记录它们。

默认日志解决的是“谁访问了”,定制日志解决的是“访问过程怎么样”。

默认格式缺什么

Nginx默认的combined格式只记录请求的开始时间、HTTP方法、状态码、响应体大小。它不记录请求的处理时长,也不记录上游服务器的响应时间。当用户说“网站慢”时,你无法从默认日志中确认慢在哪一环——是Nginx处理慢,还是PHP-FPM执行慢,还是数据库响应慢。你只能凭猜测去排查。

默认格式记录的客户端IP可能是CDN节点或负载均衡器的IP,而不是真实用户的IP。如果你的网站使用了CDN或七层负载均衡,日志中的$remote_addr记录的是最后一跳的IP,而不是访问者的真实IP。这两个缺失的信息,在故障排查和运营分析中恰恰是最需要的。

定制日志格式:log_format

Nginx通过log_format指令定义日志格式。将以下配置添加到http块中:

nginx

http {
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';
    
    access_log /var/log/nginx/access.log main;
}

main是格式名称,在access_log指令中引用。$remote_addr记录直接连接的客户端IP。$remote_user记录基本认证用户名。$time_local记录请求时间。$request记录完整请求行(方法+路径+协议)。$status记录响应状态码。$body_bytes_sent记录响应体大小。$http_referer记录来源页面。$http_user_agent记录客户端标识。$http_x_forwarded_for记录原始客户端IP(需代理传递)。

添加响应时间字段

响应时间是排查性能问题的关键字段。Nginx提供两个变量来记录时间:

$request_time:从接收客户端第一个字节到发送完最后一个字节的总耗时,包括接收请求、处理请求、发送响应三个环节。对应变量为$request_time,单位为秒,精度到毫秒。

$upstream_response_time:Nginx转发请求到上游服务器(如PHP-FPM、Tomcat)后,等待并接收完整响应所花费的时间。不包括Nginx自身的处理时间。

在日志格式中添加这两个字段:

nginx

log_format timing '$remote_addr - $remote_user [$time_local] "$request" '
                  '$status $body_bytes_sent "$http_referer" '
                  '"$http_user_agent" "$http_x_forwarded_for" '
                  'rt=$request_time ut="$upstream_response_time"';

rt标记总响应时间,ut标记上游响应时间。当rt接近ut时,说明Nginx本身处理快,慢在上游服务。当rt远大于ut时,说明慢在Nginx层(可能是网络传输慢,也可能是客户端网络慢)。

记录真实客户端IP

当网站使用CDN或七层负载均衡时,$remote_addr记录的是CDN节点或负载均衡的IP,而不是访问者的真实IP。CDN和负载均衡器通常会在HTTP头中传递原始客户端IP。对于Cloudflare,使用$http_cf_connecting_ip;对于通用CDN或代理,使用$http_x_forwarded_for

http块中添加以下配置,让Nginx从正确的位置获取客户端IP:

nginx

http {
    set_real_ip_from 10.0.0.0/8;
    set_real_ip_from 192.168.0.0/16;
    real_ip_header X-Forwarded-For;
    real_ip_recursive on;
}

不同场景的日志格式推荐

场景推荐字段用途
运维排查$remote_addr$request$status$request_time$upstream_response_time定位性能瓶颈
安全分析$remote_addr$request$status$http_user_agent$http_x_forwarded_for识别异常请求
数据分析$request$status$http_referer$http_user_agent用户行为分析

一个真实案例

某电商平台在促销活动中发现部分用户打开商品页很慢。Nginx默认日志只显示状态码200和响应大小,看不出耗时。添加$request_time$upstream_response_time后,发现$upstream_response_time平均8秒,而$request_time平均8.5秒——慢在PHP-FPM处理环节,而不是网络或Nginx。针对商品详情接口优化代码和缓存后,$upstream_response_time降到0.2秒。

最后一句

Nginx默认日志只能告诉你“有人访问了”,定制日志能告诉你“访问过程怎么样”。默认日志记录的是谁来了,定制日志告诉你他等待了多久、慢在哪个环节。响应时间和真实IP这两个字段,在故障排查和运营分析中比默认字段更有价值。去检查你的Nginx日志格式,把$request_time$upstream_response_time加进去,下次用户说“网站慢”时,你的日志里已经有答案了。

知识库

服务器缓存策略进阶:何时使用本地缓存、分布式缓存?

2026-7-24 15:11:34

知识库

MySQL性能优化入门指南:从慢查询日志到索引建立 (实战教程)

2025-8-27 11:27:07