Nightingale 告警静默(Alert Mute)HTTP API 完整指南:面向外部 A2A Agent 与 curl 的接口实战
【免费下载链接】nightingaleNightingale is to monitoring and alerting what Grafana is to visualization.项目地址: https://gitcode.com/GitHub_Trending/ni/nightingale
导读
Nightingale 的告警静默规则(alert_mute)用于在指定时间范围内按标签条件压制匹配的告警事件,是机房维护窗口、夜间批量任务免打扰、已知问题降噪的标准手段。本文以仓库内面向外部 A2A Agent 的接口说明文档 http-api.md 为主体,系统讲解静默规则的 HTTP API 全貌——包括 9 个端点的路径、方法与请求体格式、权限模型、预览与试运行校验接口、过期规则批量清理,以及"直接修改数据库"的兜底方案,并结合 router.go、router_mute.go、models/alert_mute.go、alert/mute/mute.go 等源码,深入剖析匹配引擎的判定顺序与 9 秒缓存生效机制。读完本文,外部 Agent 或运维脚本即可通过 HTTP 完成静默规则的查询、创建、更新、批量改字段、删除、命中预览与试运行全流程。
说明:应用内 AI 助手(in-app assistant)不应使用这些 HTTP 端点,而应直接调用内置功能工具(FC tools);本文档面向的是外部 A2A Agent,或在给用户提供 curl 命令时使用。
一、API 总览:一张表看懂 9 个端点
所有端点均挂在/api/n9e前缀下,路由定义位于 center/router/router.go。完整清单如下:
| 操作 | Method | Path | 说明 |
|---|---|---|---|
| 列表(跨业务组) | GET | /api/n9e/busi-groups/alert-mutes | 返回当前用户可见的静默规则;支持query搜索、分页,以及expired=1查询已过期规则 |
| 列表(单个业务组) | GET | /api/n9e/busi-group/:id/alert-mutes | 指定业务组下的静默规则 |
| 详情 | GET | /api/n9e/busi-group/:id/alert-mute/:amid | 单条规则详情 |
| 创建 | POST | /api/n9e/busi-group/:id/alert-mutes | 请求体是单个AlertMute JSON 对象 |
| 更新 | PUT | /api/n9e/busi-group/:id/alert-mute/:amid | 单对象请求体,整体替换——先 GET、再修改、再 PUT |
| 批量改字段 | PUT | /api/n9e/busi-group/:id/alert-mutes/fields | 请求体为{"ids":[...],"fields":{...}},适合批量禁用/续期 |
| 删除 | DELETE | /api/n9e/busi-group/:id/alert-mutes | 请求体为{"ids":[1,2,3]} |
| 命中预览 | POST | /api/n9e/busi-group/:id/alert-mutes/preview | 预览一条静默规则草稿会命中哪些当前活跃事件;创建大范围静默前务必先跑 |
| 试运行 | POST | /api/n9e/alert-mute-tryrun | 用规则草稿对某个历史事件做一次匹配试运行 |
| 批量清理过期 | DELETE | /api/n9e/alert-mutes | 需要 admin 权限;异步在后台清理已过期的定时(fixed-period)静默规则(周期静默不清除) |
从 router.go 的路由定义可以看到,每个端点都串联了多个中间件:rt.auth()做身份认证、rt.user()注入用户上下文、rt.perm("/alert-mutes")系列做菜单权限校验,部分写操作还叠加了rt.bgrw()(业务组读写权限)与rt.admin()(管理员权限)。
二、认证与权限模型
2.1 认证方式
所有请求都使用 Bearer Token 认证:
Authorization: Bearer <token>token为当前登录用户在 Nightingale 中签发并持久化于user_token表的访问令牌(可参考 models/user_token.go)。调用前需先通过登录/SSO 流程获取 token。
2.2 权限要求
- 创建 / 更新 / 删除:需要业务组读写权限(bgrw)+ 对应的
/alert-mutes/*菜单权限; - 列表 / 详情(只读操作):仅需业务组只读权限即可。
对应到路由中间件(router.go):
rt.perm("/alert-mutes"):基础菜单权限,覆盖列表与详情;rt.perm("/alert-mutes/add"):创建与试运行;rt.perm("/alert-mutes/put"):更新与批量改字段;rt.perm("/alert-mutes/del"):删除;rt.bgrw():业务组读写权限,创建/删除/批量改字段均要求;rt.admin():批量清理过期规则(DELETE /api/n9e/alert-mutes)额外要求系统管理员身份。
简言之:只读操作门槛低,写操作必须同时具备业务组读写权限与对应菜单权限,批量清理则必须是 admin。
三、核心数据模型:AlertMute 字段与 JSON 序列化
http-api.md明确指出"直接修改数据库(兜底)"时表名为alert_mute,其中tags/periodic_mutes/severities/datasource_ids是 JSON / 序列化字段。其数据模型定义在 models/alert_mute.go,关键点:
- DB 存储形态与 API 形态分离:
DatasourceIds、PeriodicMutes、Severities在 GORM 中映射为字符串(JSON 序列化后的文本),而对外 JSON 输出分别由DatasourceIdsJson、PeriodicMutesJson、SeveritiesJson承载;FE2DB()负责从 API 形态序列化到 DB 形态,DB2FE()负责反向解析(models/alert_mute.go); Tags字段以ormx.JSONArr存储,是一组TagFilter的 JSON 数组,每个元素形如{"key":..., "func":..., "value":...};MuteTimeType:0=固定时间区间(TimeRange),1=周期静默(Periodic);MuteType:0=屏蔽事件与通知(默认,命中后事件不产生也不通知),1=只屏蔽通知(事件照常产生记录,仅不发送通知);Activated是查询时动态计算的展示字段(gorm:"-"),表示"此刻是否处于生效时间内",并非存储状态。
Verify()(models/alert_mute.go)包含两条硬校验:
datasource_ids为空或包含0时自动归一化为[0](即"全部数据源");etime <= btime直接报错(oops... etime(%d) <= btime(%d))——这条校验对周期静默同样生效,因此即使周期匹配不读取 btime/etime,创建时也必须让两者满足etime > btime。
四、逐个端点详解与 curl 实战
4.1 列表查询
跨业务组列表:
curl -G "http://<n9e-host>:17000/api/n9e/busi-groups/alert-mutes" \ -H "Authorization: Bearer <token>" \ --data-urlencode "query=web01" \ --data-urlencode "expired=1"- 返回当前用户可见业务组下的全部静默规则;
query参数做模糊搜索(源码中是对cause字段做like匹配,见 models/alert_mute.go);expired=1用于查询已过期的固定区间静默规则(mute_time_type=0 AND etime < now)。
单业务组列表:
curl -G "http://<n9e-host>:17000/api/n9e/busi-group/12/alert-mutes" \ -H "Authorization: Bearer <token>"4.2 详情查询
curl "http://<n9e-host>:17000/api/n9e/busi-group/12/alert-mute/345" \ -H "Authorization: Bearer <token>"返回单条规则完整 JSON,包含datasource_ids、severities、periodic_mutes、tags等解析后的数组形态字段,以及动态计算的activated字段。更新前务必先 GET(见下节)。
4.3 创建
curl -X POST "http://<n9e-host>:17000/api/n9e/busi-group/12/alert-mutes" \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{ "note": "Maintenance window: mute web01 alerts", "cause": "web01 planned maintenance, expected 2 hours", "prod": "metric", "cate": "prometheus", "datasource_ids": [], "severities": [1, 2, 3], "tags": [ {"key": "ident", "func": "==", "value": "web01"} ], "mute_time_type": 0, "btime": 1737000000, "etime": 1737007200, "periodic_mutes": [], "cluster": "0" }'要点:
- 请求体是单个AlertMute 对象,不是数组;
mute_time_type=0(固定区间)时必须满足etime > btime,否则Verify()直接拒绝;datasource_ids为空数组即"全部数据源"(会自动归一化为[0]);tags为空数组意味着无条件静默该业务组内全部告警,属于高风险配置,务必谨慎;- 完整的字段表、时间模式与 tags 运算符说明见配套文档 reference.md。
4.4 更新(整体替换)
curl -X PUT "http://<n9e-host>:17000/api/n9e/busi-group/12/alert-mute/345" \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{ "note": "Maintenance window: mute web01 alerts (extended)", "cause": "maintenance extended", "prod": "metric", "cate": "prometheus", "datasource_ids": [], "severities": [1, 2, 3], "tags": [{"key": "ident", "func": "==", "value": "web01"}], "mute_time_type": 0, "btime": 1737000000, "etime": 1737014400, "periodic_mutes": [], "cluster": "0" }'关键语义:PUT 是整体替换(replaced wholesale)。从源码 models/alert_mute.go 可见,Update会把新对象的字段整体Select("*").Updates(arm)覆盖写回,仅保留Id、GroupId、CreateAt、CreateBy四个不可变字段。因此标准操作流程是:GET 详情 → 在返回 JSON 基础上修改 → 原样 PUT,任何漏传字段都会被覆盖为空值,切勿只传想改的字段。
4.5 批量改字段
curl -X PUT "http://<n9e-host>:17000/api/n9e/busi-group/12/alert-mutes/fields" \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{ "ids": [345, 346, 347], "fields": {"disabled": 1} }'fields支持任意可更新字段的键值对,典型场景:批量禁用({"disabled":1})、批量续期(修改etime)、批量改标签;- 底层走
UpdateFieldsMap(models/alert_mute.go),仅更新传入字段,不触碰其他列——与 4.4 的整体替换形成鲜明对比; - 处理器实现见 router_mute.go 的
alertMutePutFields。
4.6 删除
curl -X DELETE "http://<n9e-host>:17000/api/n9e/busi-group/12/alert-mutes" \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{"ids": [345, 346, 347]}'底层对应models.AlertMuteDel(models/alert_mute.go),按 ID 批量物理删除。应用内 AI 助手场景下删除建议走 UI(告警管理 → 告警屏蔽),或先disabled:1临时禁用(更安全)。
五、命中预览与试运行:创建大范围静默前的安全阀
这是http-api.md重点强调的两个"校验类"端点,用于在创建大范围静默前验证影响面,避免误伤。
5.1 命中预览:POST /api/n9e/busi-group/:id/alert-mutes/preview
请求体为一条 AlertMute 草稿 JSON(与创建时同构,group_id取自 URL 路径参数)。处理器alertMutePreview(router_mute.go)的逻辑是:
f.Verify()校验并解析 tags 为ITags;- 从活跃事件表
alert_cur_event中按业务组、产品、严重级别、数据源等条件取出候选事件(AlertCurEventGetsFromAlertMute); - 逐个用
common.MatchTags做标签匹配,返回所有会被这条静默命中的活跃事件列表。
curl -X POST "http://<n9e-host>:17000/api/n9e/busi-group/12/alert-mutes/preview" \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{ "note": "check impact before large mute", "prod": "metric", "cate": "prometheus", "datasource_ids": [], "severities": [1,2,3], "tags": [], "mute_time_type": 0, "btime": 1737000000, "etime": 1737007200, "periodic_mutes": [], "cluster": "0" }'如果返回的事件数量远超预期(例如空 tags 命中了整个业务组),说明影响面过大,应在创建前调整条件。
5.2 试运行:POST /api/n9e/alert-mute-tryrun
用一个规则草稿对某个具体历史事件做一次匹配试运行,返回 "event match mute" 或 "event not match mute"。处理器alertMuteTryRun(router_mute.go)的流程:
- 绑定表单:
AlertMute草稿 +EventId(历史事件 ID)+PassTimeCheck标志; - 通过
AlertHisEventGetById取历史事件并转为当前事件形态、构建 TagsMap; - 若
PassTimeCheck=true,把静默时间强制改为"每天 00:00~00:00"的周期形式,从而跳过时间窗口判断、只验证业务组/数据源/严重级别/标签是否匹配; - 调用引擎核心函数
mute.MatchMute得到匹配结果。
curl -X POST "http://<n9e-host>:17000/api/n9e/alert-mute-tryrun" \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{ "event_id": 98765, "pass_time_check": true, "alert_mute": { "note": "tryrun", "prod": "metric", "cate": "prometheus", "datasource_ids": [], "severities": [1,2,3], "tags": [{"key": "ident", "func": "==", "value": "web01"}], "mute_time_type": 0, "btime": 1737000000, "etime": 1737007200, "periodic_mutes": [], "cluster": "0" } }'该端点非常适合排查"为什么这条静默不生效"——用真实事件逐条验证草稿配置。
六、批量清理过期静默:DELETE /api/n9e/alert-mutes
固定区间的静默规则到期后不会自动删除(仅不再加载进匹配缓存),长时间运行会积累大量无效数据。管理员可通过该端点异步清理:
curl -X DELETE "http://<n9e-host>:17000/api/n9e/alert-mutes" \ -H "Authorization: Bearer <token>"- 必须 admin 权限(路由中带
rt.admin()); - 后台异步批量删除"已过期的固定区间静默"(
mute_time_type=0 AND etime > 0 AND etime < now AND create_at < now),周期静默(periodic)不会被清理; - 底层实现见 models/alert_mute.go 的
AlertMuteBatchDelete,支持按业务组限制范围与分批 limit,处理器为 router_mute.go 的alertMuteBatchDelete。
七、兜底方案:直接修改数据库
当 HTTP API 无法满足需求(例如需要跨业务组批量迁移、修复脏数据)时,http-api.md给出了最后的兜底手段:
- 表名:
alert_mute; - JSON/序列化字段:
tags(TagFilter 数组 JSON)、periodic_mutes(PeriodicMute 数组 JSON)、severities(int 数组 JSON)、datasource_ids(int 数组 JSON); - 生效机制:修改后内存缓存最长约9 秒自动重载(见 memsto/alert_mute_cache.go,轮询间隔为
time.Duration(9000) * time.Millisecond),无需重启服务; - 务必先备份再修改。
需要注意的语义细节(详见配套排障文档 troubleshooting.md):
- 已过期的固定区间静默不会加载进匹配缓存,直接改 DB 时同样遵循该规则;
prod/cate/cluster字段仅用于展示,不参与匹配,不要指望用它们过滤事件。
八、源码级原理:匹配引擎如何判定"命中静默"
理解这些 HTTP 端点返回结果的前提,是掌握底层匹配语义。核心函数MatchMute位于 alert/mute/mute.go,按固定顺序逐门校验,任一关卡失败即判定未命中:
| 顺序 | 关卡 | 源码逻辑 | 失败常见原因 |
|---|---|---|---|
| 0 | 缓存同步 | 内存缓存轮询约 9s 重载(memsto/alert_mute_cache.go) | 刚改完规则立即测试,缓存尚未刷新 |
| 1 | 业务组 | group_id隔离 | 事件与规则不在同一业务组(最常见根因) |
| 2 | 启用状态 | Disabled == 1直接返回 false | 规则被禁用 |
| 3 | 数据源 | datasource_ids非全量时,事件datasource_id必须在列表中 | 数据源不匹配 |
| 4 | 时间 | 固定区间[btime, etime]闭区间判定(IsWithinTimeRange);周期静默按星期 + HH:mm 判定(IsWithinPeriodicMute,models/alert_mute.go) | 触发时间不在窗口内;enable_days_of_week写法错误 |
| 5 | 严重级别 | severities非空时,事件Severity必须在列表中 | 级别不匹配 |
| 6 | 标签 | 多条 tagsAND 关系(common.MatchTags,alert/common/key.go) | 事件缺少任一标签或值不匹配 |
几个值得展开的引擎语义:
- 静默发生在事件评估阶段(
alert/process/process.go):命中静默的事件被直接丢弃——不落库(不产生当前/历史告警记录)、不发送通知,仅在服务日志与静默计数指标中留痕; - 不会误判恢复:被静默事件的 hash 仍会记入告警集合,因此已触发的告警不会因为静默而"假装恢复";同理,静默不会清除已产生的活跃告警——"静默生效后历史告警页仍能看到旧事件"是正常现象;
- 周期静默的时间判定不读取 btime/etime(源码 models/alert_mute.go 只看
enable_days_of_week+enable_stime/enable_etime),btime/etime 仅为通过etime > btime硬校验而存在; - 跨午夜原生支持:
enable_stime > enable_etime(如22:00~06:00)按">= stime或< etime"判定; - 星期编号0=周日 … 6=周六,时间判定使用 n9e 进程的本地时区;
in/not in运算符的值为空格分隔字符串(ParseTagFilter用strings.Fields切分,models/alert_mute.go),写成逗号分隔会匹配失败。
prod、cate、cluster三字段在MatchMute中完全不参与判定,属于纯展示字段。
九、常见坑位速查
结合配套排障文档 troubleshooting.md 与源码,外部调用方最容易踩的坑:
| 现象 | 原因 | 处理 |
|---|---|---|
etime <= btime报错 | Verify()硬校验,周期静默同样要求 | 确保etime > btime;或使用应用内工具传duration参数自动计算 |
| 周期静默在 btime/etime 边界行为异常 | 周期匹配不读btime/etime,只看星期+时段 | 想实现"仅某个月生效"需到期手动禁用/删除 |
enable_days_of_week写1-5或Monday to Friday不生效 | 引擎对空格分隔数字串做 contains 匹配 | 写"1 2 3 4 5",或用"weekday"等别名 |
in值写逗号分隔不生效 | 解析用strings.Fields(按空白切分) | 改为空格分隔 |
| tags 有 key 无 value | 空值参与精确匹配,几乎必然失配 | 先确认真实标签值再填 |
| 想屏蔽"某条告警规则" | 事件标签含rulename | 用{"key":"rulename","func":"==","value":"<规则名>"} |
| 大范围误静默 | tags 为空数组 = 静默整个业务组 | 创建前先跑preview端点核对影响面 |
十、与内置 Agent 工具的分工
http-api.md开篇即强调:应用内 AI 助手不应使用这些端点,而应使用内置 FC 工具(如create_alert_mute、update_alert_mute、list_alert_mutes、get_alert_mute_detail),工具的完整工作流见 SKILL.md。二者适用边界:
- 内置工具:运行在 n9e 进程内、已认证为当前用户,直接调用即可,支持
duration参数自动换算时间戳、空业务组时自动弹出选择表单、修改走"提案确认"机制等高级能力,是应用内推荐路径; - HTTP API:面向外部 A2A Agent,或用户明确索要 curl 命令时使用;需要自行管理 token、自行计算 btime/etime、注意 PUT 整体替换语义。
两者共享同一套数据模型与匹配引擎,因此本章讲解的字段、校验、匹配顺序与缓存机制,对两种调用方式完全一致——这也是理解本 API 全部行为的最佳捷径。
延伸阅读
- http-api.md:本文核心文档
- reference.md:静默规则完整字段表、两种时间模式、tags 运算符与完整示例
- troubleshooting.md:"静默不生效"逐门排障链与行为语义表
- models/alert_mute.go:数据模型、
Verify校验、FE2DB/DB2FE序列化与批量删除 - alert/mute/mute.go:匹配引擎
MatchMute六道关卡 - alert/common/key.go:标签匹配
MatchTags与六种运算符实现 - center/router/router.go:路由与权限中间件定义
- center/router/router_mute.go:预览、试运行、批量清理等处理器实现
【免费下载链接】nightingaleNightingale is to monitoring and alerting what Grafana is to visualization.项目地址: https://gitcode.com/GitHub_Trending/ni/nightingale
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考