Fluentd清洗Nginx日志核心是三步:Nginx输出JSON格式日志、Fluentd用tail监听并解析、通过filter插件提取/过滤/丰富字段;关键在于日志格式可控与解析规则健壮,推荐Nginx直接输出JSON而非空格分隔文本,避免正则解析错误。

Fluentd 收集并清洗 Nginx 日志流,核心是三步:配置 Nginx 输出结构化日志(推荐 JSON)、用 Fluentd 监听日志文件或转发端口、通过 filter 插件解析、过滤、丰富字段。关键不在“能不能做”,而在日志格式是否可控、解析规则是否健壮。
让 Nginx 输出可解析的 JSON 日志
默认 access_log 是空格分隔的文本,正则解析易出错。更可靠的方式是让 Nginx 直接输出 JSON:
log_format json '{"time":"$time_iso8601",'
'"remote_addr":"$remote_addr",'
'"host":"$host",'
'"request":"$request",'
'"status":$status,'
'"body_bytes_sent":$body_bytes_sent,'
'"http_referer":"$http_referer",'
'"http_user_agent":"$http_user_agent",'
'"request_time":$request_time,'
'"upstream_response_time":"$upstream_response_time"}';
<p>access_log /var/log/nginx/access.log json;</p>注意:
• 确保 $upstream_response_time 等变量在 proxy 场景下有效,否则留空或设为 "-";
• 若用 logrotate,Fluentd 需开启 refresh_interval 或配合 tail 插件的 enable_watch_timer;
• 不建议用 syslog 协议直传(时序和可靠性难保障),优先走文件 tail 或本地 TCP/UDP。
Fluentd 配置:tail + parser + filter 流水线
典型配置(fluent.conf)如下:
<source>
@type tail
path /var/log/nginx/access.log
pos_file /var/log/td-agent/nginx-access.pos
tag nginx.access
format json
time_key time
time_format %Y-%m-%dT%H:%M:%S%z
</source>
<p><filter nginx.access>
@type parser
key_name request
reserve_data true
<parse>
@type regexp
expression ^(?<method>[A-Z]+)\s+(?<path>[^ ]+)\s+HTTP/(?<http_version>[\d.]+)$
</parse>
</filter></p><p><filter nginx.access>
@type record_transformer
enable_ruby true
<record>
status_class ${record["status"] / 100 == 2 ? "success" : record["status"] / 100 == 4 ? "client_error" : record["status"] / 100 == 5 ? "server_error" : "other"}
path_clean ${record["path"].gsub(/\?.*$/, '').gsub(/\/+/, '/')}
</record>
</filter></p><p><match nginx.access>
@type stdout # 或转发到 Elasticsearch / Kafka / S3
</match></p>说明:
• format json 已能直接解析外层字段,无需额外 json parser;
• 第二个 <filter> 用 parser 提取 request 字段中的 method/path/version;
• record_transformer 添加衍生字段(如状态分类、清理后的路径),便于后续聚合;
• 所有字段都变成嵌套哈希,可在下游直接按 record["status_class"] 过滤。
常见清洗需求与对应插件
实际分析中常需以下处理,Fluentd 均有轻量方案:
-
过滤爬虫或健康检查请求:用
@type grep+ 正则匹配http_user_agent或path -
提取 URL 参数(如 utm_source):配合
@type parser的query_parser插件,或用record_transformer+ Ruby 脚本解析URI.parse(path).query -
补充地理信息:用
@type geoip2插件查remote_addr,需提前下载 GeoLite2 数据库 -
采样降噪:对高频静态资源(
path =~ /\.(js|css|png|jpg)$/)用@type sample降低 90% 日志量
验证与调试技巧
上线前务必验证解析效果:
- 用
fluentd -c fluent.conf -v启动,观察 stdout 输出是否字段齐全、无 nil 错误 - 手动向日志追加一行 JSON,看 Fluentd 是否实时捕获并转换(
echo '{"time":"..."}' >> /var/log/nginx/access.log) - 用
fluent-cat模拟发送日志:echo '{"time":"2024-01-01T12:00:00+00:00","status":200}' | fluent-cat nginx.access - 在
<filter>中临时加@type stdout,确认某阶段输出是否符合预期
不复杂但容易忽略:时间字段必须正确声明 time_key 和 time_format,否则 Fluentd 默认用接收时间,影响按小时/分钟聚合的准确性。


















