Nginx日志推送到ELK需四步:一、标准化JSON日志格式;二、用Filebeat轻量采集并直解析;三、Logstash清洗字段类型、提取URL要素、分类状态码;四、ES按天索引+ILM管理,Kibana建仪表板与地理可视化。

将Nginx日志推送到ELK(Elasticsearch + Logstash + Kibana)实现远程集中化管理,核心在于:日志采集不侵入业务、传输可靠、解析准确、存储可查。关键不是“能不能传”,而是“怎么传得稳、查得准、扩得开”。
一、Nginx日志格式标准化是前提
Logstash或Filebeat依赖固定字段解析日志。若Nginx使用默认 log_format,字段缺失(如响应时间、上游地址、请求体大小)会导致后续分析受限。
建议在 nginx.conf 的 http 块中定义结构化日志格式:
log_format main_json '{"@timestamp":"$time_iso8601",'
'"host":"$server_addr",'
'"clientip":"$remote_addr",'
'"size":$body_bytes_sent,'
'"responsetime":$request_time,'
'"upstreamtime":"$upstream_response_time",'
'"upstreamaddr":"$upstream_addr",'
'"http_host":"$host",'
'"url":"$uri",'
'"domain":"$host",'
'"xff":"$http_x_forwarded_for",'
'"referer":"$http_referer",'
'"agent":"$http_user_agent",'
'"status":"$status"}';
access_log /var/log/nginx/access.log main_json;
注意:
• 使用 $upstream_response_time 需确保 Nginx 有 upstream 配置且启用 proxy_pass;
• 若用 keepalive 或多 upstream,$upstream_addr 可能含多个地址,Logstash 中需用 split 处理;
• 时间字段统一用 $time_iso8601,避免时区/格式解析失败。
二、选择轻量可靠的日志采集器
不推荐直接让 Nginx 写入 TCP/UDP 到 Logstash(易丢日志、无缓冲、无重试)。主流方案有两种:
- Filebeat(推荐):资源占用低、支持文件监控、断网自动缓存、内置 JSON 解析与字段提取,与 ELK 同源,配置简洁;
- Fluentd(备选):插件生态丰富,适合混合日志源(如容器+宿主机),但内存占用略高。
Filebeat 示例(filebeat.yml):
filebeat.inputs:
- type: filestream
enabled: true
paths:
- /var/log/nginx/access.log
json.keys_under_root: true
json.overwrite_keys: true
json.add_error_key: true
<p>output.logstash:
hosts: ["logstash-server:5044"]
loadbalance: true
ssl.enabled: false</p>要点:
• 开启 json.keys_under_root 直接提升日志字段到顶层,免去 Logstash grok 解析;
• 生产环境建议启用 SSL 和证书校验;
• 若 Logstash 不可用,Filebeat 可临时写入本地磁盘队列(spool_size + queue.mem.events),保障不丢。
三、Logstash 做必要清洗与增强
即使用了 JSON 日志,仍需 Logstash 补充信息、过滤噪音、规范字段类型:
- 把 responsetime 和 upstreamtime 转为数字类型(默认是字符串),否则 Kibana 无法做统计图表;
- 从 url 或 uri 中提取 path、query、method(如用 dissect 或 kv 插件);
- 对 status 做分类(2xx/3xx/4xx/5xx),便于聚合;
- 丢弃健康检查日志(如 /health、/ping)、爬虫 UA、内部探测请求(加 if 判断)。
Logstash filter 示例片段:
filter {
if [responsetime] { mutate { convert => { "responsetime" => "float" } } }
if [upstreamtime] { mutate { convert => { "upstreamtime" => "float" } } }
if [url] { dissect { mapping => { "url" => "%{method} %{path} %{query}" } } }
mutate {
add_field => { "http_status_group" => "%{status}" }
}
if [status] =~ /^2\d\d$/ { mutate { replace => { "http_status_group" => "2xx" } } }
if [status] =~ /^4\d\d$/ { mutate { replace => { "http_status_group" => "4xx" } } }
if [status] =~ /^5\d\d$/ { mutate { replace => { "http_status_group" => "5xx" } } }
}
四、Elasticsearch 索引策略与 Kibana 可视化落地
避免所有日志写进一个大索引。应按天滚动(如 nginx-access-2024.06.15),并设置 ILM(Index Lifecycle Management)自动删除旧数据。
Kibana 中建议创建:
- 预设仪表板:QPS 曲线、状态码分布饼图、Top URL 响应时间、慢请求(responsetime > 2s)列表;
- 自定义字段映射:对 clientip 做 geo_point(需配合 GeoIP 插件)、url 做 keyword 类型用于聚合;
- 保存常用搜索:如 status:500 AND host:"api.example.com",方便快速定位故障。
小技巧:在 Kibana Discover 页面点击某个 clientip → “Add filter” → “Filter for value”,再点 “Save search”,下次可一键打开该 IP 的完整访问链路。










