log_format 必须定义在 http 块内且名称唯一,access_log 必须显式指定格式名才生效;否则默认使用 combined。变量拼写错误不报错但留空,真实 IP 需配合 set_real_ip_from 使用,$request_time 等关键字段需手动添加,路径须绝对并确保权限正确,reload 后新日志才用新格式。

直接说结论:log_format 必须定义在 http 块内,且名称不能重复;access_log 必须显式指定格式名才能生效,否则 fallback 到默认 combined —— 很多人改了 log_format 却没生效,就是漏了这一步。
log_format 必须放在 http 块里,且不能重名
log_format 不是全局指令,它只在 http 块中有效。放在 server 或 location 里会直接报错:unknown directive "log_format"。
常见错误是复制粘贴时把 log_format 放到了 server 段开头,或者在多个 http 块(比如 include 的文件)里重复定义同一名字,如两次写 log_format main ...,Nginx 启动会失败并提示:duplicate log_format "main"。
- 命名建议用语义化名称,比如
log_format upstream_with_time '$http_x_forwarded_for - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $request_time $upstream_response_time'; - 变量名必须用
$开头,拼写错误(如$http_x_forwared_for)不会报错,但日志里对应字段为空字符串 - 如果要记录真实客户端 IP,优先用
$http_x_forwarded_for,但注意它可能被伪造;更稳妥的做法是配合set_real_ip_from+real_ip_header X-Forwarded-For使用
access_log 必须显式引用 format 名,不能只靠位置
很多人以为只要定义了 log_format myfmt ...,再写 access_log logs/access.log; 就会自动用上 myfmt,其实不会——Nginx 默认只认 combined 和 main(如果定义过),其他格式必须显式写出名字:
access_log logs/access.log myfmt; ✅access_log logs/access.log; ❌(用的是内置 combined)
- 可以在
http、server、location任意一级设置access_log,越靠近请求匹配点的优先级越高 - 同一作用域下写多条
access_log是允许的,比如同时写入本地文件和 syslog:access_log /var/log/nginx/app.log myfmt;+access_log syslog:server=10.0.0.10:514 myfmt; - 想关闭某 location 的日志?写
access_log off;,不是注释掉
真实 IP、响应时间、代理链路这些关键字段怎么加
默认 main 格式不包含 $request_time 和 $upstream_response_time,而这两个对性能分析至关重要。加进去很简单,但要注意顺序和空格:
log_format detailed '$http_x_forwarded_for - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $request_time $upstream_response_time $upstream_addr';
-
$request_time:从接收到第一个字节到发送完响应头的时间(单位秒,精度毫秒),由 Nginx 自己计算 -
$upstream_response_time:上游服务器返回第一个字节的时间,多个 upstream 用逗号分隔;如果用的是 fastcgi,对应变量是$upstream_response_time(同名)或$fastcgi_upstream_response_time -
$upstream_addr:实际转发到的 upstream 地址,能帮你确认负载均衡是否均匀 - 别漏掉引号:像
"$request"这种带空格/特殊字符的字段必须加双引号,否则日志解析工具(如 awk、ELK)会切错列
权限、路径、reload 这些实操细节最容易卡住
配置改完,nginx -t 通过了,但日志文件就是不生成,90% 是权限或路径问题:
- 确保
access_log指定的路径目录存在,且 Nginx worker 进程用户(user指令指定的用户,如www-data或nginx)有写权限;mkdir -p /var/log/nginx && chown nginx:nginx /var/log/nginx - 路径不要用相对路径(如
logs/access.log),除非你明确知道prefix是哪;生产环境建议用绝对路径:/var/log/nginx/access.log - 改完配置必须
nginx -s reload(不是 restart),否则新格式不会加载;可以用ps aux | grep nginx看主进程时间戳是否更新 - 第一次生成日志后,检查内容是否符合预期:
tail -1 /var/log/nginx/access.log,看字段数、引号、时间格式是否对得上
最常被忽略的一点:log_format 定义后,所有引用它的 access_log 都会立即生效,但旧日志文件不会自动按新格式重写——历史日志还是老样子,只有新写入的行才用新格式。

















