Nginx 输出合法JSON日志是ELK高效采集前提,需在http块定义log_format json_log,确保每行是完整JSON、数值字段不加引号、时间用$time_iso8601;server块中用access_log启用该格式;Filebeat需设json.keys_under_root: true,Logstash用json filter解析,ES需预设@timestamp为date、status为integer类型。

Nginx 输出 JSON 格式日志是 ELK(或 Elastic Stack)高效采集与解析的前提。关键不是“加个格式就行”,而是让每行日志本身是合法、字段完整、时间可识别的 JSON,避免 Logstash 或 Filebeat 解析失败或字段丢失。
在 nginx.conf 的 http 块中定义 JSON 日志格式
直接写入结构清晰、引号和逗号规范的 JSON 字符串,推荐使用 $time_iso8601 作为时间戳字段(Kibana 默认识别 @timestamp),并确保数值型字段不加引号(如 status、body_bytes_sent、request_time):
log_format json_log '{"@timestamp":"$time_iso8601",'
'"remote_addr":"$remote_addr",'
'"remote_user":"$remote_user",'
'"body_bytes_sent":$body_bytes_sent,'
'"request_time":$request_time,'
'"status":$status,'
'"request_uri":"$request_uri",'
'"request_method":"$request_method",'
'"http_referrer":"$http_referer",'
'"http_user_agent":"$http_user_agent",'
'"http_x_forwarded_for":"$http_x_forwarded_for",'
'"host":"$host",'
'"server_addr":"$server_addr"}';
注意:
- 每个键名用双引号包裹,字符串值也用双引号,数值型字段(如
$status)不加引号,否则 ES 会存为 text 类型,无法做聚合或排序; - 行末不加逗号,最后一项后不加逗号,避免 JSON 语法错误;
- 所有变量必须存在(如
$http_x_forwarded_for在无代理时可能为空,但 Nginx 会输出"-",不影响 JSON 合法性)。
在 server 或 location 块中启用该格式
替换原有 access_log 指令,指向日志路径并指定格式名:
access_log /var/log/nginx/access.log json_log;
若同时收集 error 日志,需单独配置(error.log 不支持自定义格式,需用 Filebeat 的 multiline 或 Logstash 的 grok 处理)。
验证日志是否真正输出为 JSON
重启 Nginx 后,立即触发一次请求(如 curl http://localhost),再检查日志末行:
tail -n 1 /var/log/nginx/access.log | jq . # 若安装了 jq,可校验合法性
正常应返回格式化后的 JSON 对象,且 @timestamp 字段可被 Kibana 自动识别为时间字段。
适配采集端的关键提醒
- 使用 Filebeat 时,在
filebeat.yml中开启json.keys_under_root: true和json.overwrite_keys: true,确保 JSON 字段直接提升到根层级; - 使用 Logstash 时,input 阶段无需 grok,filter 阶段只需一行
json { source => "message" },再加date { match => ["@timestamp", "ISO8601"] }校准时间; - Elasticsearch 索引模板中,需提前将
@timestamp映射为date类型,status映射为integer,否则 Kibana 可视化会异常。
这样配置后,Nginx 日志就具备了结构化、可索引、易聚合的基础,ELK 后续环节才能稳定运行。











