nginx通过log_format输出elk兼容json日志的核心是定义结构化json字符串:需字段语义清晰、数值不加引号、字符串自动转义(escape=json)、单行合法json,并配合filebeat直解析或logstash json codec,确保@timestamp、status等字段类型正确映射至elasticsearch。

在 Nginx 中通过 log_format 输出符合 ELK(Elasticsearch + Logstash + Kibana)采集规范的 JSON 日志,核心是:**用 log_format 定义结构化 JSON 字符串,确保字段名语义清晰、类型统一、无非法字符,并兼容 Logstash 的 JSON 解析或 Elasticsearch 的动态映射**。
一、定义标准 JSON 格式的 log_format
Nginx 本身不原生支持 JSON 对象输出,需手动拼接合法 JSON 字符串。关键原则是:所有字符串值必须双引号包裹、键名固定、特殊字符(如引号、换行)需转义、避免空格干扰解析。
示例(推荐使用 escape=json 选项自动转义):
详细的 Three.js 3D 图形参考,涵盖场景设置、相机、几何体、材质、光照、动画、控制器、加载器、数学工具和调试。
log_format json_log escape=json '{"@timestamp":"$time_iso8601",'
'"host":"$server_addr",'
'"client_ip":"$remote_addr",'
'"x_forwarded_for":"$http_x_forwarded_for",'
'"request_method":"$request_method",'
'"request_uri":"$request_uri",'
'"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",'
'"upstream_addr":"$upstream_addr"}';
-
必须启用
escape=json:防止客户端传入的 UA、Referer 等含双引号或换行导致 JSON 格式损坏 -
数值字段不加引号(如
$status、$request_time),便于 Elasticsearch 自动识别为数字类型 -
时间统一用
$time_iso8601,Logstash 或 Filebeat 可直接识别为 @timestamp -
字段名建议带前缀(如
http_、upstream_),避免与 Elasticsearch 内置字段冲突
二、在 server 或 location 中启用该日志格式
定义后需在具体作用域中调用 access_log 启用:
server {
listen 80;
server_name example.com;
access_log /var/log/nginx/example-access.log json_log;
error_log /var/log/nginx/example-error.log warn;
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
}
}
- 日志路径建议按域名或服务隔离,方便 Filebeat 多实例采集或 Logstash 条件路由
- 若使用
proxy_pass,务必添加proxy_set_header X-Real-IP $remote_addr;等头,确保$remote_addr在反向代理下仍能反映真实客户端 IP - 如需记录上游响应头(如 trace_id),可用
$upstream_http_x_trace_id(需开启underscores_in_headers on并确认 upstream 返回该 header)
三、适配 ELK 采集链路的关键细节
仅输出 JSON 不够,还需保证采集端能正确解析并写入 Elasticsearch:
-
Filebeat 推荐配置:设
json.keys_under_root: true和json.overwrite_keys: true,将 JSON 字段直接提升到根层级;同时设processors.add_fields添加service: nginx等标签 -
Logstash 若介入,可用
json { source => "message" }解析,但更推荐由 Filebeat 直接解析以降低延迟和资源消耗 -
Elasticsearch 映射建议:提前创建索引模板,指定
@timestamp为 date 类型、status为 integer、request_time为 float,避免动态映射出错(如把首次出现的"0.001"当成字符串) -
注意空字段处理:Nginx 变量为空时输出空字符串(如
"upstream_addr":""),Elasticsearch 默认接受;若需统一为null,需用 Lua 模块或 Logstash mutate 过滤器后处理
四、验证与排错方法
上线前务必验证 JSON 合法性与字段完整性:
- 执行
nginx -t确保配置语法正确 - 触发一次请求后,用
tail -n1 /var/log/nginx/example-access.log | jq .检查是否可被 jq 正确解析(需安装 jq) - 检查是否有字段缺失(如
$upstream_response_time在非 proxy 场景为空,或$http_x_forwarded_for未透传) - 在 Kibana 中查看新索引的字段列表,确认
status是 number 类型而非 text,@timestamp能正确用于时间筛选










