日志监控只告诉你“有多少条异常日志”是不够的。值班人员真正需要的是:哪条日志触发了告警、日志里有哪些关键字段、是否能直接从告警事件跳到排查线索。
之前有篇日志监控文章《夜莺日志监控如何获取日志原文》,讲到夜莺监控开源版本无法在日志监控告警事件中包含日志原文,并给出了逻辑说明。文中提到 Flashduty 可以做到这一点,但配置会稍微复杂一些。
本文用 Elasticsearch SQL 查询为例,演示如何在 Flashduty 日志监控中通过“关联查询”拿到日志原文,并把需要的字段渲染到告警事件描述里。
核心要点
- Flashduty 日志告警可以先用主查询判断是否触发告警,再用关联查询获取一条匹配日志的原文字段。
- 主查询适合返回计数、聚合值或判定结果;关联查询适合返回
request_id、remote_addr等排查字段。 - 关联查询建议使用
limit 1控制返回量,避免把大量日志塞进一个告警事件。 - 备注描述可以通过
$relates引用关联查询结果,把关键字段写入告警内容。
数据准备
Flashduty 针对 ElasticSearch 做日志监控时,支持的是 Elasticsearch SQL 语法。本文演示数据如下:

上图查询的是以 fc-insight 作为 Prefix 的索引,时间范围是最近 5 分钟,并增加了 status = 502 的检索条件。这个条件后面会同时用于告警主查询和关联查询,确保告警判定与日志原文来自同一类异常数据。
告警规则如何拆成主查询和关联查询
日志告警常见有两类:
| 告警类型 | 典型做法 | 适合解决的问题 |
|---|---|---|
| 日志行数统计 | 统计带有某个关键字,或符合特定查询条件的日志行数 | 例如最近 5 分钟 Level=ERROR 或 status = 502 的日志是否出现 |
| 结构化字段聚合 | 把日志作为结构化数据,提取某一列做聚合统计 | 例如统计某个接口的平均响应时间、99 分位响应时间 |
本文场景是第一类:监控最近 5 分钟 status = 502 的日志行数。只要满足条件的日志行数大于 0,就触发告警。
第一步:用主查询判断是否告警
主查询只负责回答一个问题:是否满足告警条件。
可以配置如下 SQL:
select count(1) as total from "fc-insight*" where "@timestamp" > now() - INTERVAL 5 MINUTES and status = 502

这样配置后,告警事件可以知道满足条件的日志行数是多少,但还不知道具体是哪条日志触发了问题。要把日志原文字段带出来,需要继续配置关联查询。
第二步:用关联查询获取日志原文
关联查询负责补充上下文。这个例子里,可以继续配置一个关联查询,查询第一条满足条件的日志原文,然后把查到的内容放进告警事件描述:

select * from "fc-insight*" where "@timestamp" > now() - INTERVAL 5 MINUTES and status = 502 limit 1
这里的 limit 1 很重要。它确保关联查询只返回一条样例日志;否则当很多日志都满足条件时,所有日志都会进入告警事件,告警内容会变得非常长,反而影响值班人员快速阅读。
第三步:在备注描述中渲染关联查询结果
备注描述中,引用了关联查询的结果:
{{- range $x := $relates.R1}}
request_id: {{$x.Fields.request_id}} , remote addr: {{$x.Fields.remote_addr}}
{{- end}}
这里展示了 request_id 和 remote_addr 两个字段。实际使用时,可以根据日志结构选择更有排查价值的字段,例如接口路径、服务名、错误码、用户标识或 trace id。

$relates 对应上图中的 relate_values。告警产生之后,点击告警规则的 Triggered 按钮,就可以看到关联查询的结果。
最后生成的告警事件中会带上 request_id 和 remote_addr 两个字段的内容:

配置时的注意事项
- 主查询和关联查询的时间窗口要保持一致,否则告警触发条件和展示出来的日志样例可能不匹配。
- 关联查询只选择排查必要字段即可,避免把完整大字段、堆栈全文或大量日志写进告警描述。
- 如果日志里有
request_id、trace_id、host、service等字段,优先把这些字段放进告警描述,方便后续串联链路和定位责任对象。 - 如果同一类日志会大量出现,建议先用主查询做聚合判定,再用关联查询取样例,避免告警事件膨胀。
FAQ
Q1:为什么不直接把主查询写成 select *?
A:主查询的职责是做告警判定,最好返回稳定、可比较的数值或结果;日志原文属于排查上下文,更适合由关联查询补充。
Q2:关联查询一定要 limit 1 吗?
A:不是语法强制,但日志告警里建议限制返回量。告警事件需要便于阅读,返回一条代表性样例通常比返回大量日志更适合值班场景。
Q3:备注模板里可以展示哪些字段?
A:可以展示关联查询结果中的字段。本文示例使用 request_id 和 remote_addr,实际字段取决于日志结构和查询结果。
结语
Flashduty 的关联查询能力,可以把日志告警从“知道有异常”推进到“看到异常上下文”。主查询负责判定是否触发告警,关联查询负责补充日志原文字段,备注模板负责把这些字段展示给值班人员。
如果你的日志监控工具无法在告警事件中携带日志原文,可以参考本文的思路:将告警判定与上下文查询拆开,再把关键字段渲染到通知内容里。这样既能保留聚合告警的简洁性,也能让一线排障更快拿到线索。