Linux 日志告警规则设计案例

2次阅读

必须用 rsyslog 模板输出标准 json 日志,显式指定 timestamp 格式为 rfc3339,模板语法分号不可误写为冒号,再配合 kibana 告警配置、promql 合理聚合及 elastalert 超时与字段类型校验,才能确保日志采集、解析与告警全链路准确生效。

Linux 日志告警规则设计案例

用 rsyslog 模板打结构化日志,不然 Logstash 会漏字段

Logstash 的 grok 解析不是万能的,尤其遇到多行日志、时间戳格式混乱或字段缺失时,message 里只剩一串乱码,告警规则根本匹配不上。真正省事的做法,是在源头就让 rsyslog 输出标准 JSON —— 不依赖应用改代码,也不靠 Logstash 猜。

  • 必须在 /etc/rsyslog.conf 末尾加 template,且 Property(name="timestamp" dateFormat="rfc3339") 要显式指定,否则 Kibana 时间轴全错位
  • *.* @127.0.0.1:5044;json-template 中的分号不能写成冒号,否则 rsyslog 启动失败但不报错,日志静默丢弃
  • 测试是否生效:用 logger "test Error" 发一条日志,然后 tcpdump -i lo port 5044 -A 抓包,看到的是带 "level":"ERR" 的 JSON 才算成功

在 Kibana 里设告警,别只填“ERROR”就完事

Kibana 的 Log threshold 类型看着简单,但默认过滤器对大小写敏感、不支持通配符嵌套,message: "*Connection refused*" 实际上不会命中 "Connection refused (111)" 这类带括号的日志——因为 * 在 KQL 里只匹配单词边界,不是 shell 风格通配。

  • 正确写法是用 message: "Connection refused"(去掉星号),再配合 message: "timeout" 单独加条件,用 OR 连接
  • Time range 设为 Last 10 minutes 时,实际窗口是动态滑动的,如果采集延迟 >30s,可能漏掉刚写入但还没进 ES 的日志,建议同步检查 logstash@timestampEvent.ingested 差值
  • 触发条件选 count of documents > 5 是合理起点,但若某服务每分钟固定打 3 条 ERROR,这个阈值就形同虚设;应先查历史 count by hour 分布,再定基线

用 PromQL 告警网络流出异常,irate()rate() 别混用

监控 node_network_transmit_bytes_total 时,直接用 rate() 算 1 分钟平均,会把突发流量平滑掉;而用 irate() 又容易被单次抖动误触发。真实场景中,“流出速率过高”要的是持续压力,不是毛刺。

  • 推荐组合:avg_over_time(irate(node_network_transmit_bytes_total{device=~"eth[0-9]+"}[2m])[5m:1m]) —— 先用 irate 提取每 1 分钟内的瞬时速率,再用 avg_over_time 取过去 5 分钟的均值,抗干扰强
  • device!~'lo|docker|veth' 这类过滤必须写全,漏掉 vnetbr- 会导致虚拟网桥流量计入,误判宿主机出口带宽
  • 单位换算别硬编码:告警表达式里用 /1024/1024 得到 MB/s,但 description 模板里写 {{ $value | humanize}} MB/s 更稳妥,避免小数点后一 0

ElastAlert 规则里写 num_events,得先确认 ES 查询没超时

ElastAlert 默认用 query_key + timeframe 做聚合统计,但如果索引量大、字段没建 keyword 类型、或者 ES 查询超时(默认 10s),它会安静地返回空结果,然后规则永远不触发——连错误日志都不打。

  • 务必在 elastalert.yaml 里显式设 es_timeout: 30,并检查对应索引的 message 字段 mapping 是 text 还是 keyword;模糊匹配要用 text,聚合统计必须用 keyword
  • num_events: 3 表示 5 分钟内出现 3 次,但若日志里 hostname 字段为空,query_key: hostname 就会把所有主机日志聚成一组,导致误报;建议加 Filter 强制 hostname: "*"
  • 调试时别只看 elastalert --debug,要同时开 curl -XGET 'http://es:9200/_nodes/stats/indices/search?pretty',确认 query_time_in_millis 是否接近 timeout 值

最常被跳过的环节是时间字段对齐:rsyslog 里的 timestamp、Logstash 的 @timestamp、ES 索引的 event.ingested、Kibana 告警的时间窗口——这四个时间源只要差超过 1 分钟,规则就可能失效。别假设它们天然一致。

text=ZqhQzanResources