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

用 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的@timestamp和Event.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'这类过滤必须写全,漏掉vnet或br-会导致虚拟网桥流量计入,误判宿主机出口带宽 - 单位换算别硬编码:告警表达式里用
/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 分钟,规则就可能失效。别假设它们天然一致。