直接用 log_format 输出 json 格式日志是让 nginx 日志天然适配 elk 的最高效方式,绕开 logstash 的 grok 解析,将结构化前置到源头,提升吞吐与稳定性。

直接用 log_format 输出 JSON 格式日志,是让 Nginx 日志天然适配 ELK 的最高效方式。它绕开 Logstash 中耗性能的 grok 解析,把结构化工作前置到源头,大幅提升日志吞吐与稳定性。
定义标准 JSON 日志格式
在 /etc/nginx/nginx.conf 的 http 块内添加:
log_format json '{"@timestamp":"$time_iso8601",' '"host":"$server_addr",' '"clientip":"$remote_addr",' '"size":$body_bytes_sent,' '"responsetime":$request_time,' '"domain":"$host",' '"url":"$request_uri",' '"status":"$status",' '"method":"$request_method",' '"agent":"$http_user_agent"}';
注意几点:
- 所有字段名用双引号包裹,值为字符串的也必须加双引号(如
"$status"),数值型字段(如$body_bytes_sent)不加引号,避免解析为字符串 -
@timestamp使用$time_iso8601,Elasticsearch 能自动识别为日期类型 - 避免在 JSON 中混入未转义的换行或空格,否则 Filebeat 或 Logstash 会解析失败
正确启用该格式并处理代理真实 IP
在 server 或 location 块中替换原 access_log 行:
access_log /var/log/nginx/access.json json;
若服务前有反向代理(如 CDN、LB),需先提取真实客户端 IP:
在 http 块顶部添加:
map $http_x_forwarded_for $clientRealIp {
"" $remote_addr;
~^(?P
}
然后将日志中的 "clientip":"$remote_addr" 替换为 "clientip":"$clientRealIp",确保 Kibana 中看到的是用户真实 IP。
配合 Filebeat 实现零过滤转发
Filebeat 配置只需指定日志路径和输出目标,无需 grok 过滤:
filebeat.inputs:
- type: filestream
paths:
- /var/log/nginx/access.json
json.keys_under_root: true
json.overwrite_keys: true
json.add_error_key: true
关键参数说明:
-
json.keys_under_root: true把 JSON 字段提升到根层级,如@timestamp、status直接可用 -
json.overwrite_keys: true防止 Nginx 日志中同名字段被覆盖 - 不用写任何
dissect或grok,Logstash 可简化为纯传输角色,甚至可直连 Elasticsearch
验证与调试要点
上线前务必检查三项:
- 执行
nginx -t确保配置语法无误;重启后观察access.json是否持续写入合法 JSON(每行一个完整对象,无换行嵌套) - 用
tail -n1 /var/log/nginx/access.json | jq .验证是否能被jq正确解析,重点看@timestamp和status字段是否存在 - 在 Kibana 的 Discover 页面确认索引中字段类型:应为
date(@timestamp)、keyword(url、method)、long(status、size)等,而非全为text











