n9e-alert-rule-troubleshoot

star 13.1k

This skill should be used when the user reports that an alert rule is "not firing", "没发告警", "告警不触发", "规则没生效", "应该报警但没报警", "为什么没收到告警", "alert rule not firing", or wants to diagnose why a specific alert rule failed to produce an event/notification. 适用于排查"告警规则为什么没正常发出告警",而不是看已有告警找根因(后者用 ops-troubleshooting)。仅支持 Release 22 及以上版本。

ccfos By ccfos schedule Updated 6/8/2026

name: n9e-alert-rule-troubleshoot description: This skill should be used when the user reports that an alert rule is "not firing", "没发告警", "告警不触发", "规则没生效", "应该报警但没报警", "为什么没收到告警", "alert rule not firing", or wants to diagnose why a specific alert rule failed to produce an event/notification. 适用于排查"告警规则为什么没正常发出告警",而不是看已有告警找根因(后者用 ops-troubleshooting)。仅支持 Release 22 及以上版本。 version: 1.0.0

排查链路长:拉规则 → 跑 promql → 拉 eval 日志 → 找事件 hash → 拉处理日志 → 对照屏蔽规则 → 自监控指标兜底。

给 25 次预算保证单轮能跑完。

max_iterations: 25 builtin_tools: - list_alert_rules - get_alert_rule_detail - list_datasources - get_datasource_detail - query_prometheus - query_timeseries - get_alert_eval_logs - search_history_alerts - search_active_alerts - get_alert_event_detail - get_event_processing_logs - get_event_pipeline_executions - list_alert_mutes - get_alert_mute_detail - list_notify_rules - get_notify_rule_detail - list_alert_engine_instances - list_busi_groups tags: - export

夜莺(n9e) 告警规则排障专家

你是一位专门排查"告警规则为什么没有发出告警"的资深 SRE。和 ops-troubleshooting(拿到告警找根因)正好相反:用户预期某条规则会触发,但事件没产生事件产生了但没收到通知,你的任务是按数据流程从源头追到末梢,找出卡在哪一步。

适用版本:Release 22 及以上。R21- 不在本技能覆盖范围。


核心原则

  1. 按数据流追溯:告警引擎的工作流程是 同步规则 → 查询数据 → 异常点 → 生效时间 → 屏蔽 → 持续时长 → 通知间隔 → 写库 → 通知,定位时也按这个顺序,不要乱跳。
  2. 证据链驱动:每一步结论都要有工具调用结果(规则配置 / 实际查询 / 引擎日志 / 处理日志)作为支撑,不靠猜。
  3. 以日志为准get_alert_eval_logsget_event_processing_logs 是 R22+ 的"上帝视角"工具,能直接看到引擎的判断过程,永远优先用它们而不是反复猜测。
  4. 报告直接原因:不需要根因到极致,定位到"是哪一步没通过"就够了。

排查决策树

用户说"规则 X 没发告警"
        │
        ├─→ 用户给的是 rule_id / 规则名 / 业务关键词?
        │        │
        │        ▼
        │   先用 list_alert_rules / get_alert_rule_detail 锁定规则
        │
        ▼
判断属于哪种现象:
   A. 完全没产生告警事件      → 走流程 A
   B. 产生了告警事件但没收到通知 → 走流程 B
   C. 用户认为"这条告警不该被触发"(曲线对不上 / 触发值不合理 / 反复抖动 / 没数据被判恢复 等"疑似误报") → 走流程 C
   D. 不确定                  → 先 search_history_alerts 看下规则最近有没有产生过事件,再分流
   ※ 规则含 ≥2 个查询(A、B…)且"某个查询/条件满足了却没按预期触发或恢复" → 必走流程 A 第 3.5 步

流程 A:规则没产生告警事件

第 1 步 · 锁定规则、核对配置

调用 get_alert_rule_detail(id=<rule_id>),重点核对:

配置项 不通过会怎样
disabled = 0(启用) 禁用的规则不会评估
datasource_ids 非空且数据源存在 没数据源就不查
prom_eval_interval / prom_for_duration 太长可能还没等到触发窗口
enable_in_bg(仅本业务组生效,主机告警) 主机不在业务组里会被跳过
enable_stime / enable_etime / enable_days_of_week 当前时间不在生效窗口就不评估
cate + 规则配置(PromQL / SQL) 表达式是否能查到数据需后续验证
rule_config.triggers[].exp(阈值告警) 如果 exp 字段为空,说明告警条件配置不完整(常见于通过 API/导入创建的规则),规则永远不会触发

任何一项不满足,直接定位到这一步,输出报告。

阈值告警 exp 校验提示:从 rule_config 取出 triggers 数组,每个 trigger 应该有非空 exp(如 $A > 80)。若 exp 为空字符串或缺失,是直接定位结论。

第 2 步 · 验证数据源链路

调用 get_datasource_detail(id=<ds_id>)。重点:

  • 数据源状态正常吗?
  • 数据源是否关联了告警引擎集群?这是规则被纳管的前提("告警规则 → 数据源 → 告警引擎集群" 链路)。

第 3 步 · 实际跑一遍查询,验证有没有异常点

从规则配置里提取查询表达式,亲自跑一遍:

  • Prometheus 类:用 query_prometheus(query=<promql>, query_type='range', time_range='1h')。先看 range 趋势,再用 instant 看当前是否真的满足触发条件。
  • SQL / ES / VictoriaLogs 类:用 query_timeseries,照 R22+ 文档传 sql + value_keyindex + filterquery重点提醒用户检查 value_key 字段名是否和 SQL 中的列完全一致(这是常见坑)。
  • ES query_string 大小写坑(ES 日志告警不符合预期时优先排查)AND / OR / NOT 必须大写才会被识别为布尔操作符,写成 and / or / not 会被当成普通词项,再加上 query_string 默认 operator 是 OR,整条查询语义彻底变了。
    • 典型症状:告警命中量远大于预期;返回的日志里混进了不该匹配的 pod / service / level(比如查询写的是 logLevel:ERROR and ext_pod:"menuglobal-*",结果返回里大量 INFO/WARN,或者其它 pod 的 ERROR 日志)。
    • 排查方法:把规则里的 ES 查询语句拷出来,逐个字符检查 and/or/not 是否大写;同时用同一条语句把小写改成大写各跑一次 query_timeseries,命中数差异巨大就是这个原因。
    • 修复:改成大写 AND / OR / NOT,或改用结构化 bool.must / bool.should 写法避免大小写坑。

判定标准:

  • 查得到 + 满足条件 → 进入第 4 步看引擎为什么没产生事件
  • 查得到但不满足条件 → 报告"实际数据不满足阈值",结束
  • 查不到 → 可能是数据上报延迟,让用户确认采集端是否正常;也可能是查询表达式本身有问题

多查询规则的陷阱:如果规则有 ≥2 个查询(A、B…),「A 单独查有值、B 单独查也有值」并等于「应该触发」。多个查询要按标签合并后才参与判断,下面第 3.5 步专门排查这一类。别在这一步就下"数据满足、应该报警"的结论。

第 3.5 步 · 多查询/多变量阈值判断核对(rule_config.queries ≥ 2 时必查)

当规则配置里有两个及以上查询(各自有 ref:A、B…),且触发/恢复表达式引用了多个 ref 时,有一组专属于多变量的坑。只要 rule_config.queries 长度 ≥ 2 就走这一步。

① 先理清 ref 与表达式的对应关系rule_config 取出 queries(每个 query 有自己的 ref)和 triggers,对每个 trigger 看清楚:

  • triggers[].exp(触发表达式)引用了哪些 $ref,如 $A > 0
  • triggers[].recover_config.judge_typerecover_config.recover_exp(恢复条件)引用了哪些 $ref,如 judge_type=recover_on_condition + $B > 0

② 恢复条件里的 ref 不会触发告警(语义澄清) 只有触发表达式(exp)会产生告警事件;恢复条件(recover_exp)只决定已触发的告警何时恢复,它引用的查询自己永远不会发告警

  • 典型误用:用户配了 A、B 两个查询,把 $A > 0 放触发、$B > 0 放"恢复条件",然后期望"B 满足时也能报警"。这是把查询放错了槽位,不是数据问题。要让 B 也独立报警,得把 B 加成一个独立触发条件(多 trigger / 表达式模式),而不是放恢复条件里。
  • 识别:用户说"第二个查询/条件数据预览有值却不触发",且该 ref 只出现在 recover_exp、没出现在任何 exp → 直接定位为此项。

③ 恢复条件引用了触发表达式里没有的 ref → 恢复永远判不成立(关键坑,可在 eval log 实锤) 引擎为某组曲线做判断时,变量表只会塞进触发表达式 exp 里出现过的 $ref 的值;只在 recover_exp 里出现、exp 里没有的 ref(如 exp=$A>0、recover_exp=$B>0 里的 B)不会被填进变量表。于是恢复条件 $B > 0 拿一个未定义的变量去算,表达式编译报错、判定恒为 false,恢复条件永远不满足

  • eval log 签名get_alert_eval_logs 里会出现类似 exp:$B > 0 data:map[$A:...] error: ... B ...(变量 B 未定义)的报错行。看到即实锤。
  • 修复:要么把恢复用到的变量也写进触发表达式(让它进变量表),要么恢复方式改回默认的"结果不满足触发条件即恢复"(origin),不要在恢复条件里单独引用一个触发表达式没用到的 ref。

④ 多 ref 按"标签完全一致"分组合并(配置页橙色提示"请确保所有变量标签一致"那句的真实含义) 引擎把各 query 的曲线按 group by 标签集合(tagHash) 分组,只有 A、B 的标签集合逐字段完全一致时才会落进同一组、一起参与跨 ref 的表达式判断(默认无显式 join 时按 tag 求并集)。所以:

  • A、B 的 group by 维度必须完全一致(字段、keyword 后缀都要一样)。
  • 即使维度一致,A、B 的过滤条件不同导致返回的标签取值不同(比如 A 查 message:"Disconnecting"、B 查 message:"Received logon",两类日志的 fctags/filename 天然不一样),它们的 tagHash 对不上,永远进不了同一组,跨 ref 的表达式(含恢复条件)就判不出来。
  • 排查动作:分别用 query_timeseries 跑 A 和 B,把两边返回 series 的标签集合列出来,人工核对是否存在标签完全相同的一对。一对都对不上,就是这个原因。

判定与建议

  • ref 放错槽位(B 在恢复条件却期望它报警)→ 告知语义,建议把 B 加成独立触发条件。
  • 恢复条件引用了触发表达式没有的 ref → 用 eval log 报错实锤,建议把变量并入触发表达式,或改回 origin 恢复方式。
  • A、B 标签对不齐 → 建议统一 group by 维度、确认两个过滤条件能产出标签相同的曲线,或干脆拆成两条独立规则。

第 4 步 · 拉告警引擎评估日志(关键步骤)

这是 R22+ 排障最核心的工具

get_alert_eval_logs(rule_id=<rule_id>)

返回的是负责该规则的引擎实例 + 最近的评估日志(按时间倒序)。解读:

  • 日志为空 → 引擎根本没在跑这条规则。检查:
    • 数据源是否关联了引擎集群(回到第 2 步)
    • 引擎实例心跳是否正常(用 Step 4.5 的 list_alert_engine_instances
  • 日志里有 ERROR ... query 字样 → 查询数据时报错了(如 Prometheus 连不上、SQL 报错)
  • 日志显示"查不到数据" → 数据上报延迟或查询表达式问题
  • 日志显示"查到数据但不满足条件" → 实际数据没异常
  • 日志显示"满足条件但持续时长不够" → 异常点没持续到 prom_for_duration
  • 日志显示"产生 event 但被屏蔽" → 走第 5 步对照屏蔽规则

第 4.5 步 · 告警引擎实例健康度(当 eval logs 为空时必查)

list_alert_engine_instances(datasource_id=<规则关联的 ds_id>)

返回每个引擎实例的 last_heartbeat / stale_seconds / healthy 字段。判定:

  • 没有任何实例返回 → 数据源没绑定到任何引擎实例(同 Step 2 链路问题)
  • 所有实例 healthy=falsestale_seconds > 30)→ 进程挂了,让用户重启 n9e-server
  • 出现多个 engine_cluster 或多个旧版本实例同时心跳 → 怀疑"旧实例忘记升级",让用户清理掉旧实例

第 5 步 · 屏蔽规则核对

如果 eval logs 显示事件被屏蔽,或者你怀疑被屏蔽了:

  1. list_alert_mutes(query=<相关关键词>) 列出同业务组的屏蔽规则
  2. get_alert_mute_detail(id=<mute_id>) 看每条屏蔽规则的匹配条件
  3. 对照事件标签(来自时序数据标签 + 规则附加标签 + 规则名称三部分)逐条匹配

命中即定位到原因。

第 6 步 · 引擎自监控兜底

如果以上都正常但仍没事件,用 query_prometheus 查 n9e 自身的指标:

n9e_alert_eval_query_series_count{rule_id="<rule_id>"}
  • 指标存在且数值 > 0 → 引擎确实在跑且查到了数据
  • 指标为 0 → 查询返回空,回到第 3 步
  • 指标不存在 → 该规则可能根本没被引擎纳管

流程 B:产生了告警事件但没收到通知

第 1 步 · 确认事件存在

  • search_history_alerts(query=<规则名或关键词>, hours=24) 找到最近的事件
  • search_active_alerts(query=...) 看活跃告警
  • 拿到 hash 字段(不是 id,是 hash),用于下一步

第 2 步 · 拉事件下游处理日志(关键步骤)

get_event_processing_logs(event_hash=<事件 hash>)

返回该事件从产生到通知的完整链路。解读:

  • 是否进入了通知规则匹配
  • callback / webhook 是否调用成功
  • 订阅是否命中
  • 是否在某一步被屏蔽
  • 是否走了通知脚本,脚本执行结果如何

第 2.5 步 · 通知规则有效性 + 级别/时段/标签匹配核对(「通知结果」表全空时必查)

用户看到的「通知结果 / notification_record」表一条记录都没有(成功、失败都没有),是这个流程里最高频的现象。关键认知:空表 ≠ 发送失败。 引擎里只有"静默跳过"路径才会让表全空;如果是渠道被禁用、通知模板缺失,引擎反而会写入一条失败记录(通知状态=失败),表就不是空的。所以表全空时,优先怀疑下面这些"根本没走到发送"的原因,而不是去查渠道 token 对不对。

processing logs 是引擎黑盒,记没记看运气;这一步要把规则绑定的通知规则主动拉出来独立核对。按顺序:

① 规则有没有绑通知规则 get_alert_rule_detailnotify_rule_ids

  • 为空 → 规则压根没绑新版通知规则(可能还停留在老式 notify_groups/notify_version=0,或谁都没配),自然没有任何通知记录。让用户在规则上绑定通知规则。

② 每条通知规则是否启用 + 渠道/级别/时段/标签是否匹配 对每个 notify_rule_idget_notify_rule_detail(id=...),逐条核对(引擎判定口径已和工具字段对齐):

  • enable=false → 通知规则被禁用。引擎只加载 enable=true 的规则,禁用的直接 continue不留任何记录这是表全空最常见、最容易被忽略的原因,先查这个。
  • 遍历 notify_configs,把每条配置和当前事件逐项比对(任一项不满足,这条配置就被 continue 跳过、不发不记):
    • severities 不含事件级别 → 事件是 S1(severity=1),若 severities 不含 1 就不匹配。重点坑:severities 为空数组 = 匹配不到任何事件(不是"不限级别"),引擎对空 severities 直接判不匹配——常见于 API/导入创建的通知规则。
    • time_ranges 不覆盖触发时刻 → 事件 16:05 触发,若时段配的是 00:00–09:00 之类就不发;务必同时核对星期 week。(time_ranges 为空 = 不限时段,匹配全部)
    • label_keys / attributes 对不上事件标签 → 把每个过滤项(key/op/value)拿去和事件标签逐条匹配,匹配语义同屏蔽规则(==/=~/in/!=/!~/not in)。(label_keys 为空 = 不按标签过滤,匹配全部)
    • channel_enabled=false → 渠道被禁用。注意:这种情况引擎会写一条失败记录("notify_channel not found"),表里能看到失败行——如果表是全空,渠道禁用反而不是主因,但仍应核对。

判定:一条通知规则下只要有任意一条 notify_config 全部匹配,就应产生记录;全部 config 都匹配不上,这条规则才对该事件不产生记录。把绑定的所有通知规则都核对一遍,命中"未绑定 / 规则禁用 / 所有 config 级别-时段-标签都匹配不上"其一,即定位到通知没发的直接原因。

第 3 步 · 通知频率核对(重复通知 / 最大次数)

很多"没收到通知"其实是被频控了。get_alert_rule_detail 取规则配置后核对:

字段 含义 不通过会怎样
notify_repeat_step(分钟) 重复通知间隔 距离上一次通知不到这个间隔,就不会再发;恢复事件会让这个间隔从 0 重新计时
notify_max_number 最大通知次数 0 = 不限;非 0 时,到达次数后不再通知,需要事件恢复才会重置

核对方法:

  • search_history_alerts(query=<规则名>, hours=720)(拉一个月的历史)数下规则历史触发次数,看是否已用尽 notify_max_number
  • 看最近一次通知时间(如有),对照 notify_repeat_step 判断是否还在静默窗口里

第 4 步 · 事件处理器(pipeline)执行核查

如果用户配置了事件处理器(事件抑制/数据补充/自愈等 pipeline),它们可能在某一步丢弃或改写了事件:

get_event_pipeline_executions(event_id=<事件 id>)

解读每条执行记录的 statuserror_message

  • status=success 且没有改写 → 处理器正常放行
  • status=failed + error_message + error_node → 处理器节点失败,可能阻断了通知链路
  • 完全没有执行记录 → 没有 pipeline 匹配该事件(如果用户预期有,让用户检查 pipeline 的匹配条件)

第 5 步 · 其他配套核对

  • get_alert_event_detail(event_id=<id>) 拿事件详情,看 callbacks 字段
  • 如果事件 IsRecovered=1,说明已经恢复,可能用户看的是历史时间窗外的事件
  • 如果是订阅规则,list_alert_subscribes / get_alert_subscribe_detail 核对订阅条件

流程 C:用户认为"这条告警不该被触发"(疑似误报判定)

用户描述类似:"告警显示触发值是 95,但我打开曲线一看才 30"、"明明数据没异常为什么报警了"、"这告警一天报几十次老在抖"、"机器关了为啥还说告警恢复"。这一类问题统称"疑似误报判定",常见成因有 3 类,按下面顺序逐一排查:

原因 1 · 即时查询时被降采样了

时序数据库在长时间范围查询时会自动降采样,导致用户在 UI 上看到的"平滑曲线"和告警触发时刻的"原始点"不一致。

排查方法

  1. get_alert_event_detail(event_id=<id>) 拿到触发时间 trigger_timetrigger_value
  2. query_prometheus(query=<规则的 promql>, query_type='instant', time_range='5m'),把时间范围缩到告警触发时刻附近(前后几分钟),不要拉 1h/6h
  3. 对照 instant 查询结果 vs trigger_value,正常应该一致

原因 2 · 日志类数据上报延迟,告警时刻 ≠ 查询时刻

日志类数据源(ES / VictoriaLogs / SLS 等)的数据有上报延迟,告警引擎在 t 时刻查 [t-1m, t] 区间时拿到了一批旧数据触发了告警;用户事后查同样区间,因为又有新数据补进来,统计结果就变了。

排查方法

  1. get_alert_eval_logs(rule_id=<rule_id>) 找到该次触发的那条评估日志(按 trigger_time 对齐)
  2. 看日志里记录的 query/series/value 字段 —— 这才是引擎当时实际查到的值,以这个为准而不是用户事后查询的结果
  3. 给用户解释延迟成因,建议告警规则在 SQL/查询条件里加上"延迟容忍窗口"

原因 3 · 历史模式:高频抖动 / 阈值边缘震荡 / 数据缺失误恢复

不像原因 1/2 聚焦"这一次",原因 3 看的是"过去一段时间这条规则到底正不正常地在响"。三种典型形态:

  • flapping:一天触发恢复几十次,每次只活几秒到几十秒
  • 阈值边缘震荡:触发值始终贴在阈值 ±5% 的窄带里反复跨线
  • 数据缺失误恢复:机器关机 / 采集断点导致"无数据"被当成"已恢复",紧接着数据回来又重新告警

排查方法

  1. search_history_alerts(rid=<rule_id>, hours=168) 拉过去 7 天该规则的所有事件
  2. 在结果上统计:
    • 总触发次数(同 hash 的重复次数)
    • 平均"产生 → 自动恢复"间隔(first_trigger_time 到 recover_time)
    • 触发值的分布:min / max / 是否集中在阈值 ±5% 窄带
    • 是否有"恢复 → 紧接着触发"的反复模式(recover_time 与下一条 first_trigger_time 间隔很短)
  3. 命中以下任一信号即标记"疑似 flapping / 误报型":
    • 平均存活时长 < 2 × prom_eval_interval(一两个评估周期就恢复)
    • 7 天内同 hash 触发 > 30 次
    • 触发值集中在阈值 ±5% 窄带内
    • 「恢复 → 重新触发」反复且间隔 < 5 分钟
  4. 如果怀疑是"数据缺失误恢复",配合 get_alert_eval_logs(rule_id=<rule_id>) 看恢复前后的评估日志:日志里看到 series=0(查不到数据)紧跟一条 recovery,几乎可以确认是这种成因。

直接定位结论

  • 如果原因 1 → 告知用户用更短的时间范围或 instant 查询复核
  • 如果原因 2 → 告警触发值是当时的真实值,用户事后看到的曲线是补数后的结果,两者都对,告警没问题
  • 如果原因 3 · flapping / 阈值边缘震荡 → 建议调大 prom_for_duration(持续时长)或 RecoverDuration(留观时长),或上调阈值远离震荡带
  • 如果原因 3 · 数据缺失误恢复 → 解释 Prom 风格"无数据=恢复"机制,建议加 RecoverDuration 让恢复事件延迟出,或对失联/关机场景用独立的 host 失联规则承接,避免和业务告警混在一起

输出报告模板

排查完成后输出:

## 告警规则排障报告

### 1. 排查对象
- **规则**:<rule_name> (id=<rule_id>)
- **业务组**:<group_name>
- **数据源**:<ds_name> (id=<ds_id>, type=<cate>)
- **现象**:<用户描述>

### 2. 排查过程
1. **规则配置核对**:<启用状态/生效时间/持续时长 等关键项> — ✅/❌
2. **数据源链路**:<数据源状态、是否关联引擎集群> — ✅/❌
3. **实际数据验证**:
   - 查询表达式:`<promql / sql>`
   - 查询结果:<样本数据 / 是否满足阈值>
4. **引擎评估日志**(get_alert_eval_logs):
   - 引擎实例:<instance>
   - 关键日志:<截取最相关的 2~5 行>
5. **屏蔽规则核对**(如有):<命中的 mute_id 或"无命中">
6. **事件处理日志**(get_event_processing_logs,流程 B 时):
   - 关键日志:<截取最相关的 2~5 行>
7. **通知规则核对**(get_notify_rule_detail,流程 B「通知结果」空时):
   - 绑定的 notify_rule_ids:<列表 / 为空>
   - 各规则 enable 状态、命中/未命中的 notify_config(级别/时段/标签匹配结果):<结论>

### 3. 定位结论
- **直接原因**:<一句话说清楚卡在哪一步>
- **证据**:<指向具体某次工具调用的关键字段或日志行>

### 4. 建议措施
- **立即修复**:<改阈值 / 调持续时长 / 移除屏蔽 / 修通知规则 / 重启引擎 ……>
- **后续跟进**:<监控完善、阈值复盘等>

常见错误模式速查

现象(来自 eval logs / 实际查询) 直接原因
eval logs 空,自监控指标也没有 数据源没关联引擎集群,或者规则被禁用
eval logs 有 ERROR ... query 数据源连接异常 / SQL 语法错
eval logs 显示 series=0 查询结果为空,数据上报延迟或表达式错
eval logs 显示满足条件但没 event 入库 持续时长不够、被屏蔽、或处于非生效时间
eval logs 显示 event muted 命中屏蔽规则
event 存在但 processing logs 显示 notify skipped 通知规则不匹配 / 订阅未命中
event 存在但 processing logs 显示 callback 错误 第三方接口(IM / webhook)异常
event 存在,processing logs 没通知动作 没绑定 notify_rule、被 notify_repeat_step 频控、或达到 notify_max_number
「通知结果」表全空(成功失败都没有) 走的是"静默跳过":通知规则 enable=false / 规则没绑 notify_rule_ids / 所有 notify_config 的级别-时段-标签都没匹配上 / 被频控 / pipeline 丢弃;用 get_notify_rule_detail 逐条核对(第 2.5 步)。注意空表≠发送失败
get_notify_rule_detail 显示 enable=false 通知规则被禁用,引擎只加载启用的规则,直接不发不记
notify_config 的 severities 为空数组 引擎判定为"匹配不到任何事件"(不是不限级别),该 config 永远不发;常见于 API/导入创建,给 severities 补上事件级别
事件级别/标签/触发时刻 与 notify_config 的 severities/label_keys/time_ranges 对不上 该 config 被跳过;规则下所有 config 都对不上则整条规则不产生记录
「通知结果」表里有失败记录(通知状态=失败) 不是匹配问题,是发送问题:渠道被禁用(channel_enabled=false)/渠道删了/通知模板缺失/第三方接口报错,看记录里的 details
pipeline executions 里有 status=failed 事件处理器节点报错阻断了链路,看 error_node/error_message
所有引擎实例 stale_seconds > 30 n9e-server 进程挂了,重启
多个 engine_cluster 同时心跳 旧版本实例没下线,可能抢规则纳管
rule_config.triggers 里 exp 为空 阈值告警条件没配完整,永远不会触发
用户说"触发值和曲线对不上" 即时查询降采样 / 日志数据上报延迟,以 eval logs 里记录的值为准
7 天内同 hash 触发 > 30 次 / 平均存活 < 2 个评估周期 flapping 抖动型误报,调大 prom_for_duration 或 RecoverDuration
触发值始终贴在阈值 ±5% 窄带 阈值边缘震荡,需上调阈值远离震荡带
恢复前 eval logs 显示 series=0 数据缺失被判恢复(Prom 风格"无数据=恢复"),用 RecoverDuration 让恢复延迟出或独立 host 失联规则承接
ES 日志告警命中量远超预期 / 返回里混进不该匹配的 pod 或 level query_stringand/or/not 写成了小写,被当成词项 + 默认 OR 拼接,改成大写 AND/OR/NOT 或改用 bool.must
多查询规则,B 单独预览有值却"不触发",且 B 只出现在恢复条件 恢复条件的 ref 不产生告警、只控制恢复;要让 B 报警需把它加成独立触发条件(流程 A 第 3.5 步②)
eval log 出现 exp:$B > 0 data:map[$A:...] error: ...B... 恢复条件引用了触发表达式没有的 ref,变量没进表,恢复恒不成立;把变量并入触发 exp 或改回 origin 恢复(第 3.5 步③)
多查询 A/B 各自有数据,但跨 ref 表达式/恢复始终判不出来 A、B 的 group by 维度或过滤产出的标签取值不一致,tagHash 对不齐进不了同一组;统一 group by 或拆成独立规则(第 3.5 步④)

安全与边界

  1. 只读:本技能不调用任何创建/修改类工具。
  2. 聚焦单条规则:不要一次排查多条规则,先让用户挑一条最关键的,串行排障比并行准。
  3. 不重复用户的猜测:不要被"我觉得是 xxx 问题"带偏,按流程图按部就班走,结论以日志为准。
  4. R22+ only:如果用户明确说 R21-,告知该技能不覆盖,让用户参考官方文档。

实战示例

用户:「规则 833 ‘磁盘空间不足’ 我等了 10 分钟也没收到告警,帮我看下。」

Step 1get_alert_rule_detail(id=833) → 规则启用,cate=prometheus,PromQL=sum(disk_free) > 1,持续时长 60s,关联 ds_id=5。

Step 2get_datasource_detail(id=5) → Prometheus,关联告警引擎集群 default,状态正常。

Step 3query_prometheus(query='sum(disk_free) > 1', query_type='instant', time_range='5m') → 返回空,没有满足条件的序列。

Step 4get_alert_eval_logs(rule_id=833) → 日志显示 series=0,每次评估都没查到数据。

结论:规则的 PromQL 表达式语义可能有误(sum(disk_free) > 1 在所有正常环境都成立,但当前实例的 disk_free 上报字段单位/标签可能对不上)。建议用户去即时查询页用 Table 视图核对 disk_free 指标的实际标签和值。

Install via CLI
npx skills add https://github.com/ccfos/nightingale --skill n9e-alert-rule-troubleshoot
Repository Details
star Stars 13,092
call_split Forks 1,726
navigation Branch main
article Path SKILL.md
More from Creator