使用nginx原生log_format输出标准json日志是对接elk最轻量稳定的方式,需满足每行一条合法json、字段值为基本类型、顶层结构扁平化三项硬性要求,并配合escape=json转义与logstash json_lines codec直采。

直接用 Nginx 的 log_format 输出标准 JSON 格式日志,是对接 ELK(Elasticsearch + Logstash + Kibana)最轻量、最稳定的方式——无需额外解析插件,Logstash 可直采,Elasticsearch 能自动识别字段类型,Kibana 查看时各字段天然可筛选、聚合、可视化。
JSON 日志格式必须满足的三个硬性要求
ELK 对“可直入 JSON 日志”有明确约定,否则 Logstash 会丢弃或报错:
-
每行一条完整、合法的 JSON 对象:不能有多行 JSON,不能有注释,不能有 trailing comma;推荐用
ngx_http_log_module原生支持的escape=json参数自动转义 -
所有字段值必须为字符串、数字、布尔或 null:Nginx 变量如
$status、$request_time默认是字符串,但需确保不混入空格、换行等非法字符;建议对关键数值字段显式用0或-占位,避免字段缺失 -
顶层结构扁平化,避免嵌套对象:Elasticsearch 不支持动态嵌套 JSON 字段(除非提前定义 mapping),所以不要写
"http": {"method": "$request_method"},应写成"http_method": "$request_method"
推荐的 log_format JSON 模板(含关键字段与容错处理)
以下模板已在生产环境验证,兼容 Logstash 的 json_lines codec 和 Elasticsearch 8.x 的 dynamic mapping:
log_format json_combined 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,'
'"request_time":$request_time,'
'"upstream_response_time":"$upstream_response_time",'
'"upstream_status":"$upstream_status",'
'"http_referrer":"$http_referer",'
'"http_user_agent":"$http_user_agent",'
'"ssl_protocol":"$ssl_protocol",'
'"ssl_cipher":"$ssl_cipher",'
'"request_id":"$request_id"'
'}';
说明:
DMap GL地图JSAPI(dmapgl)开发指南。用于编写、审查、调试 DMap 地图 API 代码,涵盖地图初始化、覆盖物渲染、图层管理、事件处理、控件交互等任务。当用户提及 dmap、dmapgl、jsapi‑gl 或相关地图开发需求时自动触发。
-
escape=json是关键,它会自动转义双引号、换行符等,防止 JSON 结构被破坏 - 数值型字段如
status、body_bytes_sent去掉引号,Elasticsearch 会自动映射为long类型;字符串字段保留引号,映射为keyword或text -
$upstream_response_time和$upstream_status在非代理场景可能为空,Nginx 会输出-,Logstash 的json_lines可正常处理为字符串;若需统一为null,需配合 Lua 或 map 指令预处理
Logstash 配置只需两步,无需 filter 解析
既然日志已是标准 JSON 行格式,Logstash 可跳过 grok,大幅提升吞吐:
input {
file {
path => "/var/log/nginx/access.log"
start_position => "end"
sincedb_path => "/dev/null"
codec => "json_lines"
}
}
output {
elasticsearch {
hosts => ["http://es:9200"]
index => "nginx-access-%{+YYYY.MM.dd}"
}
}
注意点:
- 必须用
json_linescodec,不是json;后者只处理单条 JSON,无法流式读取多行日志文件 - 确保 Nginx 日志轮转后 Logstash 能识别新文件(可通过
fileinput 的ignore_older和close_older控制) - 首次写入时,Elasticsearch 会基于首条日志自动创建 index template,建议后续手动定义 template 固定字段类型(如将
request_time设为float)
Kibana 中快速启用字段分析与告警
日志进入 Elasticsearch 后,在 Kibana → Stack Management → Index Patterns 中创建对应 pattern(如 nginx-access-*),系统会自动加载所有字段。此时可立即:
- 在 Discover 中用
status: 500或request_time > 2.0实时筛选慢请求或错误 - 用
http_method、request_uri做 Terms 分析,识别高频接口或异常路径 - 基于
@timestamp和request_time创建 SLO 监控看板,如“P95 响应时间趋势” - 对
client_ip做地理分布聚合(需开启 GeoIP 处理,可在 Logstash filter 中添加,不影响日志格式)
不复杂但容易忽略:确保 Nginx 的 $time_iso8601 时区与 Elasticsearch 集群一致(通常设为 UTC),否则 Kibana 时间范围筛选会偏差。










