Nginx通过log_format escape=json输出合法JSON日志,Filebeat直采解析并推送至ES,ES需预设索引模板定义request_time为float、remote_addr为ip等类型,Kibana基于@timestamp构建状态码分布、响应时间趋势等可视化看板。

在 Nginx 中输出结构化 JSON 日志,并通过 ELK(Elasticsearch + Logstash + Kibana)集中采集、解析与可视化,是现代日志管理的常见实践。关键在于:Nginx 负责按 JSON 格式输出日志;Logstash(或 Filebeat + Logstash/ES Ingest Pipeline)负责接收、解析、丰富日志字段;Elasticsearch 存储并索引;Kibana 提供查询与仪表盘。
1. 配置 Nginx 输出标准 JSON 日志
Nginx 本身不直接支持 JSON 日志,但可通过 log_format 指令结合双引号、转义和变量拼接,生成合法 JSON 字符串。推荐使用 escape=json(Nginx 1.11.8+)避免注入与格式错误:
log_format json_log escape=json '{'
'"@timestamp":"$time_iso8601",'
'"remote_addr":"$remote_addr",'
'"remote_user":"$remote_user",'
'"body_bytes_sent":$body_bytes_sent,'
'"request_time":$request_time,'
'"status":$status,'
'"request":"$request",'
'"request_method":"$request_method",'
'"http_referrer":"$http_referer",'
'"http_user_agent":"$http_user_agent",'
'"upstream_addr":"$upstream_addr",'
'"upstream_response_time":"$upstream_response_time",'
'"host":"$host"'
'}';
access_log /var/log/nginx/access-json.log json_log;
注意:
• 确保所有字符串字段用双引号包裹,数字字段不加引号(如 $body_bytes_sent);
• 使用 escape=json 自动转义特殊字符(如引号、换行),防止 JSON 解析失败;
• 重启 Nginx 后检查日志文件是否生成合法 JSON 行(每行一个 JSON 对象,无逗号分隔)。
2. 选择轻量采集器:Filebeat 替代 Logstash 做日志收集
生产环境更推荐用 Filebeat(而非 Logstash)读取 Nginx JSON 日志文件,因其资源占用低、可靠性高。Filebeat 可直接解析 JSON 行(无需额外 filter),再转发至 Logstash 或直送 Elasticsearch:
# filebeat.yml
filebeat.inputs:
- type: filestream
enabled: true
paths:
- /var/log/nginx/access-json.log
json.keys_under_root: true
json.overwrite_keys: true
json.add_error_key: true
<p>output.elasticsearch:
hosts: ["<a href="https://www.php.cn/link/7626051f62ed396b34abd92fc91a7814">https://www.php.cn/link/7626051f62ed396b34abd92fc91a7814</a>"]
index: "nginx-access-%{+yyyy.MM.dd}"</p>说明:
• json.keys_under_root: true 将 JSON 内部字段提升到根层级(如 "status":200 → ES 中为 status: 200);
• json.overwrite_keys: true 防止与 Filebeat 默认字段冲突;
• 若需字段转换(如将 request_time 转为浮点数)、IP 地理信息 enrich 或条件过滤,可启用 output.logstash 并在 Logstash 中用 filter { json { source => "message" } } 进一步处理。
3. 在 Elasticsearch 中配置索引模板与字段类型
JSON 日志中的数值字段(如 request_time, body_bytes_sent)若被 ES 自动映射为 text,将无法用于聚合或范围查询。应在写入前定义索引模板:
PUT _index_template/nginx_access_template
{
"index_patterns": ["nginx-access-*"],
"template": {
"mappings": {
"properties": {
"@timestamp": { "type": "date" },
"status": { "type": "integer" },
"body_bytes_sent": { "type": "long" },
"request_time": { "type": "float" },
"remote_addr": { "type": "ip" },
"request_method": { "type": "keyword" },
"host": { "type": "keyword" }
}
}
}
}
要点:
• 使用 index_patterns 匹配 Filebeat 生成的索引名(如 nginx-access-2024.05.20);
• 显式声明 request_time 为 float,否则可能被识别为 text;
• remote_addr 设为 ip 类型后,Kibana 可自动识别 IP 段、支持地理地图可视化;
• 模板需在第一个日志写入前创建,否则首次自动映射会生效且不可更改(除非重建索引)。
4. 在 Kibana 中快速构建 Nginx 监控看板
完成数据摄入后,在 Kibana 中创建索引模式(nginx-access-*),即可开始分析:
- 用 Discover 实时查看原始 JSON 日志,验证字段是否正确提取;
- 新建 Dashboard,添加可视化:
- 请求状态码分布:用 Pie chart,分组字段选
status; - 响应时间趋势:用 Line chart,Y 轴为
Average of request_time,X 轴为@timestamp(按分钟/小时聚合); - Top 访问 IP:用 Top N,字段选
remote_addr; - 错误请求详情:用 Table,筛选
status >= 400,展示request、http_user_agent、upstream_response_time。
- 请求状态码分布:用 Pie chart,分组字段选
- 保存 Dashboard 后,可设置定时刷新、邮件告警(如 5xx 错误率超阈值)或嵌入外部系统。
不复杂但容易忽略:确保 Kibana 中时间字段选的是 @timestamp(而非 event.created 或默认字段),否则时间筛选和趋势图会失效。


















