十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Nightingale(n9e)告警订阅规则(alert_subscribe)实战指南:跨团队抄送、告警升级与排障

Nightingale(n9e)告警订阅规则(alert_subscribe)实战指南:跨团队抄送、告警升级与排障 Nightingalen9e告警订阅规则alert_subscribe实战指南跨团队抄送、告警升级与排障【免费下载链接】nightingaleNightingale is to monitoring and alerting what Grafana is to visualization.项目地址: https://gitcode.com/GitHub_Trending/ni/nightingaleNightingale 的告警订阅alert_subscribe是在通知阶段对告警事件做复制 二次路由的机制它按条件筛选事件、克隆一份副本并交给关联的通知规则继续派发从而实现跨团队抄送CC、告警升级N 分钟未处理再通知他人、跨业务组收告警、把零散规则的事件聚合到统一出口等典型场景。本文基于仓库内 SKILL.md 及其配套的 reference.md、troubleshooting.md、http-api.md并结合引擎源码与数据模型完整讲解订阅规则的配置字段、新旧两版通知路由、五个可落地的配置示例、创建/编辑/排障工作流以及底层实现原理读完即可在 n9e 中独立完成订阅规则的搭建与问题排查。一、先建立正确的心智模型订阅发生在通知阶段订阅规则不是一个独立的告警源它依附在已有告警事件之上属于通知阶段的能力。在 alert/dispatch/dispatch.go 中Dispatch在完成事件本身的派发后会调用handleSubs处理订阅原始事件照常走它自己的通知链路不受订阅影响每一条匹配的订阅都会克隆一份事件副本按订阅配置改写后再走一遍通知链路dispatch.go#L723-L729 的if !isSubscribe { e.handleSubs(event) }体现了这一点因此订阅是加法语义不拦截、不替换原始通知。如果同一个人同时被配在两条链路上会收到两遍这是设计使然。从引擎匹配链dispatch.go#L752-L789 的subMatches可以确认订阅的匹配条件是全部 AND并按固定顺序检查enabled → datasource → prod → cate → tags → 业务组名 → 持续时长 → 严重级别任何一个门不通过该订阅即被跳过。还有三个容易被误解的点先明确下来group_id只是管理归属权限不参与事件匹配。订阅天然可以接收跨业务组的事件想只订阅某个业务组的事件要使用busi_groups过滤条件。新版路由notify_version1克隆事件的出口被改写为订阅指定的notify_rule_ids克隆事件的callbacks 默认被清空见 models/alert_subscribe.go#L450-L477 的ModifyEvent防止再次命中原规则的回调。配置变更最长 9 秒内生效内存缓存轮询周期为 9 秒。在 memsto/alert_subscribe_cache.go#L110-L118 的loopSyncAlertSubscribes中可以看到duration : time.Duration(9000) * time.Millisecond的轮询实现无需重启服务。二、核心配置结构一个 JSON 对象说清楚订阅规则的配置是一个单一 JSON 对象不是数组核心结构如下{ name: Subscription rule name, note: Notes, disabled: 0, prod: , cate: , datasource_ids: [], cluster: 0, rule_ids: [], severities: [1, 2, 3], for_duration: 0, tags: [], busi_groups: [], extra_config: {}, notify_version: 1, notify_rule_ids: [] }逐字段的完整说明见 reference.md核心要点如下severities必填新旧版本校验都会强制要求非空models/alert_subscribe.go#L116-L118 中if len(s.SeveritiesJson) 0 { return errors.New(severities is required) }[1,2,3]表示全部严重级别。新版必须notify_version1 非空notify_rule_ids先用list_notify_rules拿通知规则 ID若还没有合适的通知规则先通过create_notify_rule创建再回来。注意版本 1 下旧版的 redefine 类字段redefine_severity/redefine_channels/webhooks等会被校验主动清空见下文新旧版本对比。rule_ids为空 订阅所有告警规则的事件只想订阅特定规则时用list_alert_rules拿 ID。for_duration秒 仅当告警持续时长超过该值时转发是告警升级的开关0 不限。多个tags/busi_groups条目之间全部是 ANDbusi_groups匹配的是事件的业务组名称key 约定写成groups实际匹配由 func/value 驱动。prod/cate参与匹配但语义较弱prod非空时为精确匹配cate只有填host时才有真实过滤效果其它值等价于不过滤。拿不准时两者都留空字符串。datasource_ids空数组 所有数据源cluster固定为0V5 遗留字段。三、过滤条件的完整字段表tags/busi_groups的元素结构统一为{ key: tag name, func: match operator, value: match value }支持的运算符funcfunc含义value 示例精确匹配web01!不相等web01~正则匹配web.*!~正则不匹配web.*in在列表中空格分隔web01 web02 web03not in不在列表中空格分隔web01 web02常用 tagident机器标识、rulename告警规则名、__name__指标名以及自定义业务标签。严重级别取值值含义1一级告警Critical2二级告警Warning3三级告警Info完整字段表数据模型见 models/alert_subscribe.go 的AlertSubscribe字段类型必填说明namestring是订阅规则名notestring否备注disabledint否0启用默认1禁用。禁用的订阅在缓存层直接被过滤完全不参与匹配group_idint64是管理归属业务组决定谁能查看/编辑不参与事件匹配prodstring否产品类型非空时对事件的 RuleProd精确匹配空 不过滤。常见值metric/logging/hostcatestring否数据源类型当前实现只有host有真实过滤效果空 不过滤datasource_idsint[]否数据源 ID 列表空数组或含0 全部工具会自动归一化为[0]事件无数据源dsId0时跳过此过滤clusterstring否恒为0V5 遗留字段rule_idsint[]否订阅的告警规则 ID 列表空 订阅所有告警规则的事件全局订阅severitiesint[]是订阅的严重级别新旧版本均校验非空[1,2,3] 全部for_durationint64否秒。仅当告警持续时长trigger_time - first_trigger_time超过该值才转发——用于告警升级如300 持续 5 分钟未恢复才转发0 不限tagsarray否事件标签过滤多条 ANDbusi_groupsarray否按事件的业务组名称过滤多条 AND元素{key:groups,func:~,value:production.*}key 按约定写groups实现中 key 不参与匹配func/value 匹配事件的 GroupName四、通知配置新版 vs 旧版字段类型说明notify_versionint1新版推荐通过通知规则转发0旧版直接填用户组 渠道notify_rule_idsint[]新版必填非空克隆事件的出口被改写为这些通知规则新版notify_version1校验会清空所有旧版字段user_group_ids、redefine_channels/new_channels、redefine_webhooks/webhooks、redefine_severity/new_severity。这一点在 models/alert_subscribe.go#L120-L133 的Verify中有直接实现版本 1 下这几个字段被逐一置零/置空。换句话说改写严重级别/渠道是旧版能力新版要改级别/渠道请在通知规则层做路由对应 notify-rule-copilot。旧版notify_version0字段仅在维护存量配置时才会遇到字段说明user_group_ids接收用户组 ID空格分隔字符串如1 2指定了就必须同时指定new_channelsredefine_severity/new_severity为 1 时克隆事件的严重级别改为 new_severityredefine_channels/new_channels为 1 时克隆事件的通知渠道改为 new_channels空格分隔redefine_webhooks/webhooks为 1 时克隆事件的回调改为 webhooksJSON 数组未启用时克隆事件的 callbacks 会被清空防止再次命中原始回调——这条对新版同样适用extra_config扩展配置 JSON 对象引擎没有固定用途照抄{}即可五、五个可直接落地的完整示例示例 1订阅所有 Critical 告警并转发到值班通知规则最常见{ name: Subscribe to all Critical alerts, note: CC all critical alerts to the on-call chain, disabled: 0, prod: , cate: , datasource_ids: [], cluster: 0, rule_ids: [], severities: [1], for_duration: 0, tags: [], busi_groups: [], extra_config: {}, notify_version: 1, notify_rule_ids: [1] }示例 2按标签订阅特定机器组的告警{ name: Subscribe to web cluster alerts, note: CC alerts from all web-prefixed machines to the web team, disabled: 0, prod: metric, cate: , datasource_ids: [], cluster: 0, rule_ids: [], severities: [1, 2, 3], for_duration: 0, tags: [ {key: ident, func: ~, value: web.*} ], busi_groups: [], extra_config: {}, notify_version: 1, notify_rule_ids: [1] }示例 3告警升级——指定规则持续 5 分钟未恢复后通知二线{ name: CPU alert escalation, note: CPU-related alerts that persist unrecovered for 5 minutes, escalate to second-line, disabled: 0, prod: metric, cate: , datasource_ids: [1], cluster: 0, rule_ids: [10, 11], severities: [1, 2], for_duration: 300, tags: [], busi_groups: [], extra_config: {}, notify_version: 1, notify_rule_ids: [2] }示例 4跨业务组订阅——只接收 production 业务组下的数据库告警{ name: Subscribe to production database alerts, note: CC database-related alerts under the production business group to the DBA, disabled: 0, prod: metric, cate: , datasource_ids: [], cluster: 0, rule_ids: [], severities: [1, 2], for_duration: 0, tags: [ {key: rulename, func: ~, value: .*database.*|.*MySQL.*|.*Redis.*} ], busi_groups: [ {key: groups, func: ~, value: production.*} ], extra_config: {}, notify_version: 1, notify_rule_ids: [2, 3] }示例 5聚合告警事件统一转发到工单系统{ name: Forward alerts to the ticketing system, note: Warning-and-above alerts are uniformly forwarded to the internal ticketing system via a notification rule, disabled: 0, prod: , cate: , datasource_ids: [], cluster: 0, rule_ids: [], severities: [1, 2], for_duration: 0, tags: [], busi_groups: [], extra_config: {}, notify_version: 1, notify_rule_ids: [5] }六、工作流一创建订阅规则确定业务组管理归属用list_busi_groups拿group_id。如果用户已点名业务组或前端已弹出业务组表单直接使用其 ID不必再问。确定关联通知规则用list_notify_rules拿notify_rule_ids新版路由的通知出口。可选限定订阅范围只想订阅某些告警规则用list_alert_rules拿rule_ids想按标签/业务组/严重级别/时长收窄填对应过滤字段。调用create_alert_subscribe把第 1 步的业务组作为group_id传入也可以放进 config 里config传单个 JSON 对象字符串不是数组。如果省略group_id工具会自动弹出业务组选择表单用户选完后恢复本次创建。汇报结果工具返回{id, name, group_id, disabled, notify_rule_ids, url}简要汇报订阅条件和通知出口即可把规则名以内链形式展示nameurl 是返回的/alert-subscribes/edit/id用户可直接点击进入配置页核对。七、工作流二编辑与排障用list_alert_subscribes/get_alert_subscribe_detail拿到规则 ID 和当前状态确认要改什么。调用update_alert_subscribe基于提案proposal调用后立即向用户展示变更清单并暂停用户确认后系统自动持久化——确认步骤不经过你id必填config只含要改的字段增量补丁未指定的字段保持原值数组字段如 tags/severities/rule_ids/notify_rule_ids/busi_groups/datasource_ids提供即整体替换——先拿 detail 里的现有数组在其基础上构造完整的新数组再传入。常见操作临时禁用 传 config{disabled:1}缓存层直接过滤立即完全失效恢复 {disabled:0}调整升级阈值{for_duration:600}切换通知出口{notify_rule_ids:[...]}先用list_notify_rules确认 ID业务组管理归属不可变更删除没有站内工具——让用户在 UI 完成告警管理 → 订阅规则。当用户说订阅了但没收到任何东西时按 troubleshooting.md 中的链路逐门检查并主动指出最可能失败的门常见for_duration 设太大、busi_groups 名称对不上、notify_rule_ids 指向的通知规则本身配置不对确认是某个门的配置问题后可直接用update_alert_subscribe修复。八、排障链路订阅了但没收到任何东西引擎匹配链在 alert/dispatch/dispatch.go 的handleSub/subMatches中按以下顺序求值任何一个门失败即跳过该订阅请按序检查#检查项常见失败原因0缓存同步刚改完规则内存缓存最多滞后9 秒1disabled规则被禁用disabled1缓存层直接过滤2数据源datasource_ids不是全部且事件datasource_id不在列表中3prodprod非空且不等于事件的 RuleProd注意是精确匹配4cate填了host但事件不是主机类型其它值不会导致不匹配5标签多条tags是 ANDin值写成逗号分隔会导致不匹配必须空格分隔6业务组名称busi_groups匹配事件的业务组名称——按名称硬绑的条件在业务组改名后会失去目标正则没覆盖全名也会失配7时长for_duration大于事件已持续时长trigger_time - first_trigger_time——刚触发的告警必然不匹配必须等持续足够长后的下一轮通知周期8严重级别severities未包含事件的严重级别9下游出口以上全过、克隆事件已产生但notify_rule_ids指向的通知规则本身配置不对渠道/接收人/适用属性不匹配→ 转交 notify-rule-copilot 排障另外先确认源头原始告警事件必须真的产生——订阅不会凭空变出事件如果事件被静默在求值阶段被拦截它根本到不了订阅这一步。九、行为语义速查回答用户问题时可引用行为语义订阅会替换原始通知吗不会。原始事件照常走自己的通知链路订阅克隆一份副本额外转发。如果同一个人被配在两条链路上会收到两遍——这是设计使然会再次命中回调webhooks吗不会。克隆事件的 callbacks默认清空models/alert_subscribe.go#L460-L467 的ModifyEvent只有旧版显式redefine_webhooks1时才携带订阅自己的 webhooks订阅范围受 group_id 限制吗不受。group_id只是管理归属权限订阅天然接收所有业务组的事件用busi_groups/rule_ids/tags收窄for_duration如何生效比较事件的trigger_time - first_trigger_time。事件首次触发时差值为 0 必然不匹配只有告警反复通知到第 N 次、差值超过阈值后那次事件的克隆才被转发——所以升级依赖告警规则本身配置了重复通知新版能改写严重级别/渠道吗不能。notify_version1时Verify会清空 redefine_* 字段请在通知规则层做级别/渠道路由恢复事件也会被订阅吗走同样的匹配链恢复通知是否发送取决于下游通知规则的配置如is_recovered属性过滤变更多久生效缓存每 9 秒轮询一次最多 9 秒无需重启怎么判断事件是否被订阅转发克隆事件携带sub_rule_id订阅规则 ID在通知记录/事件详情中可见十、其他常见坑现象原因处理创建报severities is required新旧版本都必填至少填[1,2,3]创建报no notify rules selectednotify_version1但notify_rule_ids为空先用list_notify_rules拿 ID没有就先创建通知规则创建报new_channels is required旧版指定了user_group_ids但没填new_channels补new_channels或改用新版保存后 redefine 字段全没了新版 Verify 主动清空旧版字段预期行为不是数据丢失升级订阅从不触发告警规则没有配置重复通知notify_repeat_step0事件不会第二次来让用户检查告警规则的重复通知间隔全局订阅事件量爆炸rule_ids/tags/busi_groups 全空 复制所有事件至少加一层过滤或在下游通知规则收窄业务组改名后订阅失配busi_groups按名称匹配改用~正则或改名时同步订阅十一、验证方法站内get_alert_subscribe_detail核对字段get_notify_rule_detail核对下游出口。HTTP给用户命令POST /api/n9e/alert-subscribe/alert-subscribes-tryrun用历史事件 ID 订阅草稿试运行显示在哪个步骤匹配失败新版甚至会执行通知规则的真实测试发送。先试跑、再保存。真实验证触发一条匹配的告警然后去历史告警 → 详情查看是否出现携带sub_rule_id的克隆事件及其通知记录。十二、HTTP API供外部 A2A Agent / 给用户 curl 命令时使用站内 AI 助手不得使用这些端点应使用内置 FC 工具。认证Authorization: Bearer token。路由定义在 center/router/router.go。操作方法路径说明列表跨业务组GET/api/n9e/busi-groups/alert-subscribes当前用户可见业务组下的订阅列表单业务组GET/api/n9e/busi-group/:id/alert-subscribes详情GET/api/n9e/alert-subscribe/:sid创建POST/api/n9e/busi-group/:id/alert-subscribesBody 为单个AlertSubscribe JSON 对象group_id 取自 URL更新PUT/api/n9e/busi-group/:id/alert-subscribesBody 为数组[{...}]与创建相反按显式字段列表更新但仍建议先 GET 详情、改完整对象再 PUT删除DELETE/api/n9e/busi-group/:id/alert-subscribesBody{ids:[1,2,3]}试跑POST/api/n9e/alert-subscribe/alert-subscribes-tryrunBody{event_id:历史事件 ID,config:{...订阅草稿...}}逐门校验匹配新版还会执行通知规则的真实测试发送权限创建/更新/删除需要业务组读写权限bgrw 对应的/alert-subscribes/*菜单权限列表只需只读权限。直接改库最后手段表alert_subscribe其中tags/busi_groups/webhooks/extra_config/notify_rule_ids等是 JSON/序列化字段内存缓存约 9 秒自动重载无需重启改前先备份。十三、源码级原理一次订阅转发的完整链路把文档中的流程落到源码上订阅的完整生命周期是求值产出事件告警规则求值产生AlertCurEvent进入 alert/dispatch/dispatch.go 的Dispatch派发流程。原始通知照常发送HandleEventNotify用NotifyGroupDispatch、GlobalWebhookDispatch、EventCallbacksDispatch等 handler 合并出通知目标并go e.Send(...)异步发送dispatch.go#L706-L728。收集订阅非订阅事件会调用handleSubs通过collectSubscribes从alertSubscribeCache取出规则维度订阅keyRuleId和全局订阅key0两类候选dispatch.go#L738-L750。逐门匹配subMatches依次检查IsDisabled → MatchCluster(数据源) → MatchProd → MatchCate → MatchTags → MatchGroupsName → ForDuration 时长 → SeveritiesJson 严重级别全过才继续dispatch.go#L752-L789。克隆与改写handleSub以值传递拷贝事件副本避免污染原事件调用sub.ModifyEvent(event)改写副本清空 callbacks、写入 notify_rule_ids / notify_groups 等打上event.SubRuleId sub.Id标记记录 subscribe 日志后再次进入HandleEventNotify(event, true)走通知链路dispatch.go#L791-L803。isSubscribetrue时 handler 集合只剩NotifyGroupDispatch与EventCallbacksDispatchdispatch.go#L706-L710。缓存热加载订阅表由 memsto/alert_subscribe_cache.go 的SyncAlertSubscribes启动后台loopSyncAlertSubscribes每 9 秒全量同步一次先查统计、有变化才重载因此配置改动最长 9 秒生效、无需重启。理解这条链路后订阅只是通知阶段的加法路由这一心智模型就有了代码级支撑它不干预告警求值只在事件已经产生之后做复制 二次派发这也是为什么升级、跨组抄送、聚合转发这些场景都由它承载。【免费下载链接】nightingaleNightingale is to monitoring and alerting what Grafana is to visualization.项目地址: https://gitcode.com/GitHub_Trending/ni/nightingale创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表