Nginx通过log_format自定义JSON日志格式,字符串字段加双引号并转义特殊字符,数值字段不加引号,推荐使用Nginx 1.19.10+的$json安全变量(如$http_user_agent_json),并在access_log中指定该格式以输出合法单行JSON。

在 Nginx 中实现 JSON 格式日志输出,核心是通过 log_format 指令自定义日志格式,并用引号、转义和变量拼接构造合法 JSON 字符串。Nginx 本身不解析 JSON,但能原样输出符合 JSON 语法的字符串,供下游(如 Filebeat、Fluentd 或 Loki)采集解析。
定义 JSON 日志格式
在 http 块中添加如下配置(注意:所有字段值需用双引号包裹,特殊字符如空格、引号需转义;变量如 $time_local 会自动展开):
log_format json '{"@timestamp":"$time_iso8601",'
'"remote_addr":"$remote_addr",'
'"remote_user":"$remote_user",'
'"request":"$request",'
'"status":$status,'
'"body_bytes_sent":$body_bytes_sent,'
'"http_referer":"$http_referer",'
'"http_user_agent":"$http_user_agent",'
'"request_time":$request_time,'
'"upstream_response_time":"$upstream_response_time",'
'"host":"$host"}';说明:
- 每行末尾的逗号需紧跟前一个字段的右引号,换行仅为了可读性,Nginx 会自动拼接;
- 数值型字段(如
$status、$request_time)不加引号,保持 JSON 数字类型; - 字符串字段(如
$http_user_agent)必须加双引号,且内部双引号需用\"转义(若 UA 含引号,建议用$http_user_agent_json变量替代,见下文); -
$time_iso8601比$time_local更适合作为时间戳,因它符合 ISO 8601 标准且含时区。
处理特殊字符(如引号、换行)
默认变量可能含非法 JSON 字符(如 User-Agent 中的双引号)。推荐启用 nginx-module-json(第三方模块)或使用内置的 JSON 安全变量(Nginx 1.19.10+):
- 升级到 Nginx ≥ 1.19.10 后,可用
$http_user_agent_json、$arg_x_json等自动转义变量; - 若无法升级,可配合
map指令做简单替换(如将双引号替换为空字符串),但无法覆盖所有情况; - 避免在 JSON 字段中直接使用未处理的
$request或$args,建议拆分为$request_method、$uri、$args单独输出。
在 server 或 location 中启用 JSON 日志
指定 access_log 使用刚定义的 json 格式,并确保路径有写入权限:
server {
listen 80;
server_name example.com;
<pre class="brush:php;toolbar:false;">access_log /var/log/nginx/access.json json;
error_log /var/log/nginx/error.log;
location / {
proxy_pass http://backend;
# 其他配置...
}}
注意:
- 日志文件后缀(如
.json)仅为标识,不影响内容; - 多个
access_log指令可共存(如同时输出文本日志和 JSON 日志); - 重启 Nginx 后生效:
nginx -t && nginx -s reload。
验证与调试技巧
生成一条请求后,检查日志是否为单行合法 JSON(每条日志一行,无换行符):
- 用
tail -n1 /var/log/nginx/access.json | jq .验证解析是否成功(需安装 jq); - 若报错 “invalid character”,常见原因是某个变量值含未转义双引号或换行,可临时改用
$http_user_agent_json替代; - 测试时用
curl -H "User-Agent: test\"abc" http://localhost模拟含引号 UA,观察日志是否崩坏。


















