log_format 必须在 http 块中定义,server 或 location 块中使用会报错;定义后通过名称在 access_log 中引用,需注意变量大小写、语义区别、缓冲控制及 JSON 转义问题。

log_format 指令必须在 http 块里定义
直接写在 server 或 location 块里会报错:unknown directive "log_format"。Nginx 要求所有 log_format 必须位于 http 上下文中,哪怕你只打算在某个 server 里用它。定义后,才能在 access_log 中通过名称引用。
常见错误是把格式定义和日志启用混在一起写,比如在 server 里先写 log_format myfmt ... 再写 access_log /var/log/nginx/my.log myfmt —— 这会导致启动失败。
- 正确做法:在
http块顶部或靠近顶部位置统一定义,例如:log_format myfmt '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $request_time';
- 定义后,在任意
server块中用access_log /path/to/log myfmt;启用 - 同一个
log_format名称不能重复定义,否则 Nginx reload 会失败
常用变量要区分大小写且不能拼错
Nginx 变量名严格区分大小写,$request_time 写成 $Request_time 或 $request_Time 都不会被解析,而是原样输出字符串。更隐蔽的问题是变量本身不存在却误以为可用,比如 $upstream_response_time 在没有配置 upstream 的场景下始终为空,但不会报错。
几个高频误用点:
-
$host是请求头里的 Host 字段(可能被客户端伪造),$server_name才是当前 server 块配置的域名,二者语义不同 -
$request包含方法、URI 和协议,但不包含请求体;想记录 POST 数据需用$request_body(仅限log_format+access_log组合时有效,且要求请求体未被缓冲或提前读取) -
$status是响应状态码,$upstream_status才是上游返回的状态码(反向代理场景才可能非空)
access_log 的 buffer 和 flush 参数影响日志实时性
默认情况下,Nginx 会缓存日志写入,导致 tail -f 看不到最新条目,尤其在低流量站点上可能延迟数秒甚至更久。这不是格式问题,但常被误认为 log_format 没生效。
解决方法是在 access_log 指令中显式控制缓冲行为:
- 加
buffer=4k控制内存缓冲区大小(默认一般为 64k 或由系统页大小决定) - 加
flush=5s表示最多缓存 5 秒就刷盘,适合调试期;生产环境建议设为flush=1s或更高以平衡 I/O 和实时性 - 完全禁用缓冲(不推荐):用
access_log /path/to/log myfmt buffer=0;,每次请求都写磁盘,高并发下性能明显下降
注意:buffer 和 flush 必须写在同一行 access_log 指令中,拆成两行无效。
JSON 格式日志要注意引号和特殊字符转义
很多人想输出 JSON 日志方便采集(如 Filebeat),但直接写 log_format json '{"ip":"$remote_addr"}'; 会出问题:当 $remote_addr 含有双引号或换行时,JSON 不合法;另外 Nginx 不自动转义,得靠变量本身或外部工具补救。
稳妥做法是用 Nginx 官方模块 ngx_http_log_module 支持的 $escapewin 类变量(需 1.11+),或借助第三方模块如 nginx-json-log;但最轻量的方式仍是预处理:
- 避免在日志中嵌入不可控内容,比如不用
$request,改用$request_method $uri $server_protocol拆开记录 - 对可能含特殊字符的字段(如
$http_user_agent)加一层 shell 过滤(需配合 logrotate 或外部脚本),或交由日志收集端解析时处理 - 如果必须强 JSON,建议在
access_log指向管道,由下游程序做转义(例如access_log "|/usr/bin/python3 /opt/json-escape.py" json;)
真正难的不是写对格式,而是确保每条日志都能被下游稳定解析——字段缺失、编码混乱、长度超限,这些比语法错误更难排查。











