nginx 1.11.8+ 支持 escape=json 参数,自动对变量值中的双引号、反斜杠、换行符等做 json 转义,确保日志字段符合 json 字符串规范;需在 http 块定义 log_format,字符串变量加引号并后置 escape=json,数值字段不加引号,再通过 access_log 启用。

Nginx 从 1.11.8 版本开始支持 escape=json 参数,用于在 log_format 中自动对变量值做 JSON 转义(如双引号、反斜杠、换行符、控制字符等),从而安全地将日志输出为结构化 JSON 格式。关键不是“生成完整 JSON 对象”,而是确保每个字段值都符合 JSON 字符串规范,避免解析失败。
配置带 escape=json 的 log_format
在 http 块中定义日志格式,所有需写入 JSON 字段的变量后加上 escape=json:
log_format json_combined escape=json
'{'
'"time_local":"$time_local",'
'"remote_addr":"$remote_addr",'
'"request_method":"$request_method",'
'"request_uri":"$request_uri",'
'"status":$status,'
'"body_bytes_sent":$body_bytes_sent,'
'"http_user_agent":"$http_user_agent",'
'"http_referer":"$http_referer",'
'"request_time":$request_time,'
'"upstream_response_time":"$upstream_response_time"'
'}';
注意:
- 整个日志行是手动拼接的 JSON 对象字符串,
escape=json只作用于每个双引号内的变量值(如"$http_user_agent"),不处理大括号、逗号、冒号等固定字符; - 数字类型字段(如
$status、$body_bytes_sent)不要加引号,否则会被当成字符串;若加了引号又用了escape=json,Nginx 会报错(语法不允许对非字符串变量用 escape); -
$upstream_response_time是字符串(可能为空或多个时间,如"0.002, 0.005"),必须加引号并启用escape=json; - 所有字符串变量(
$xxx)只要出现在 JSON 字符串值位置,都建议加escape=json,防止特殊字符破坏 JSON 结构。
启用该日志格式并写入文件
在 server 或 location 块中使用 access_log 指令指定格式:
access_log /var/log/nginx/access.json json_combined;
确保目标目录可写,且 Nginx 进程有权限创建/追加该文件。重启或重载 Nginx 生效:
nginx -t && nginx -s reload
验证日志是否合法 JSON
查看一行日志示例(已美化):
{
"time_local":"21/Jan/2025:14:22:36 +0800",
"remote_addr":"192.168.1.100",
"request_method":"GET",
"request_uri":"/api/v1/users?id=123&name=John%20Doe",
"status":200,
"body_bytes_sent":1247,
"http_user_agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36",
"http_referer":"https://example.com/dashboard",
"request_time":0.023,
"upstream_response_time":"0.021"
}
可使用命令快速校验:
head -1 /var/log/nginx/access.json | python3 -m json.tool
如果报错,常见原因包括:某变量值含未转义的换行符($request_uri 或 $http_user_agent 中混入恶意换行)、漏写 escape=json、数字字段误加引号。
进阶建议
提升 JSON 日志实用性:
- 添加唯一请求 ID:
map $request_id $req_id { default "$request_id"; },再在 log_format 中用"request_id":"$req_id"; - 过滤空值或敏感字段:用
map预处理变量(如隐藏密码参数),再写入日志; - 配合 logrotate 按天切分,并用
gzip压缩,避免单文件过大; - 若需完整结构化采集(如对接 ELK),推荐用
nginx-json-log等模块或 Fluentd/Ngrok 做后续解析与转发,而非仅靠 Nginx 原生能力。











