nginx 的 log_format 指令支持自定义访问日志结构,需在 http 块定义、server 或 location 中通过 access_log 引用;常用变量包括 $remote_addr、$request_time、$upstream_response_time、$status、$body_bytes_sent、$http_referer、$http_user_agent、$request_id 等;注意变量阶段可用性、响应头用 $sent_http_*、空值默认显示“-”,调试需 nginx -t 验证并 tail 实时观察。

Nginx 的 log_format 指令允许你完全自定义访问日志的输出结构,包括添加请求头、响应头、变量、时间戳等任意支持的 Nginx 变量。关键在于正确使用内置变量,并注意变量在不同阶段的可用性(例如响应头变量需在响应发送后才可记录)。
常用自定义字段及对应变量
以下是最常被添加的扩展字段及其推荐写法:
-
真实客户端 IP:用
$http_x_forwarded_for或更可靠的$realip_remote_addr(需配合set_real_ip_from和real_ip_header使用) -
上游响应时间:用
$upstream_response_time(反向代理场景),多个 upstream 时以逗号分隔,如"0.002, 0.004" -
请求处理总耗时:用
$request_time(单位秒,精度毫秒,如0.003) -
状态码 + 响应体大小:直接用
$status和$body_bytes_sent,注意后者不含响应头字节数 -
Referer 和 User-Agent:用
$http_referer和$http_user_agent,注意带http_前缀表示请求头 -
请求 ID(用于链路追踪):用
$request_id(需启用ngx_http_core_module,Nginx 1.11.0+ 默认支持)
定义与引用 log_format 的完整写法
必须在 http 块中定义,然后在 server 或 location 中通过 access_log 引用:
http {
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$request_time $upstream_response_time $http_x_forwarded_for';
<pre class="brush:php;toolbar:false;">server {
access_log /var/log/nginx/access.log main;
# 其他配置...
}}
注意:log_format 名称(如 main)不能含空格或特殊符号;每行末尾加空格便于阅读,但非必需;单引号内可换行,Nginx 会自动拼接。
进阶技巧与避坑提示
-
记录响应头字段:用
$sent_http_*,例如$sent_http_x_cache_status(需确保该 header 确实由 Nginx 发出) -
条件记录字段:Nginx 原生不支持 if 判断日志字段,但可用
map预生成变量,再引入 log_format -
避免日志膨胀:慎用
$request_body(默认不记录,开启需配置client_body_buffer_size和log_subrequest on,且仅对小请求安全) -
中文或特殊字符乱码:确保日志文件编码为 UTF-8,Linux 下建议用
locale -a | grep -i utf检查环境,并统一终端查看工具编码 -
变量为空时显示破折号:Nginx 默认输出
-,无需额外处理;若需自定义空值(如显示"-"或"none"),可用map映射
验证与调试方法
修改配置后务必执行 nginx -t 检查语法;用 tail -f /var/log/nginx/access.log 实时观察日志是否按预期输出;可临时加一个简单 location 测试:
location /test-log {
return 200 "ok";
}然后 curl http://your-domain/test-log 并检查日志行是否包含你新增的字段,确认变量值是否符合预期(比如 $request_time 是否非零、$upstream_response_time 在直连时不为空字符串等)。











