Linux 日志集中收集与分析方案

1次阅读

rsyslog 转发日志丢数据主因是 udp 不可靠及队列不足,应改用 tcp(@@)并配置磁盘队列;filebeat 漏日志因未设 close_eof:true 且误用 tail_files:true,导致容器重启前日志未被读取。

Linux 日志集中收集与分析方案

为什么 rsyslog 转发日志到 syslog-ng 会丢数据?

因为默认 UDP 传输不保证送达,且 rsyslog 的队列配置没跟上吞吐压力。真实场景里,应用批量打日志(比如 Java 应用启动时刷几百行)极易触发丢包。

  • 改用 TCP:在 rsyslog 配置里把 @10.0.1.5:514 换成 @@10.0.1.5:514(双 @ 表示 TCP)
  • 启用磁盘队列:在 /etc/rsyslog.conf 中加 $ActionQueueFileName fwdRule1$ActionQueueMaxDiskSpace 1g$ActionQueueSaveOnShutdown on
  • syslog-ng 端要配 so-rcvbuf(1048576),否则内核缓冲区满后直接丢包

filebeat 收集容器日志时为什么漏掉重启前的日志?

因为 docker 默认日志驱动是 json-file,容器退出后,filebeat 如果没及时读完或没开启 close_eof,残留日志就永远卡在文件末尾不动。

  • 确保 filebeat.inputs 中设 close_eof: true,让文件关闭后立即提交 offset
  • 避免用 tail_files: true 启动——它只读新追加内容,跳过已有日志
  • 如果容器生命周期极短(/var/lib/docker/containers/**/*-json.log 并配 scan_frequency: 1s

loki + promtail 做日志检索,为什么 label 过滤总不生效?

因为 promtailpipeline_stages 没正确提取字段,或者 loki 查询时用了等值匹配但实际 label 是空字符串或 null。

  • 检查 promtail 日志输出是否带预期 label:运行 curl -s localhost:9080/metrics | grep promtail_lines_total,确认采集量正常
  • pipeline_stages 里用 regex 提取前先加 labels 阶段,比如 {job="nginx", cluster="prod"},避免依赖日志内容动态生成
  • Loki 查询写成 {job="nginx"} |= "502",别写 {job=~"nginx"}——正则匹配开销大,且容易误中未打 label 的旧日志

elasticsearch 存日志太占磁盘,index.lifecycle.name 不起作用?

因为 ILM 策略没绑定到索引模板,或者索引名没按模板规则创建(比如手动 PUT /mylog-2024-01-01 绕过了模板)。

  • 先确认模板是否存在:GET _index_template/logs_template,看 index_patterns 是否匹配你的索引名(如 "logs-*"
  • 策略必须显式引用:模板里要有 "lifecycle": {"name": "logs_retention"},不能只在策略里定义
  • 别用 date_math 手动算索引名;用 logs-%{+yyyy.MM.dd} 这类动态 pattern,让 rollover 自动触发

真正麻烦的是跨集群时间同步——如果采集端和 ES 节点时钟差超过 5 秒,ILM 会拒绝 rollover,这个点多数人压根没想到查 NTP 状态。

text=ZqhQzanResources