关于 kubesense-alerts
用于通过读取和创建流程处理 KubeSense 告警的 Skill。它区分正在触发的告警实例、规则定义和历史记录,并指导通过经过验证的 MCP 工具或可审核的导入 JSON 创建规则。
主要功能
- 01查看触发中的告警和规则定义
- 02检查告警详情与历史
- 03查找以往告警调查
- 04通过验证创建单条规则
- 05验证或准备导入 JSON
适用场景
- 01调查触发告警及其历史
- 02判断告警是长期反复还是新出现
- 03通过 MCP 工具创建单条告警规则
- 04准备或验证批量告警导入
MCP 相关
指导 MCP 客户端使用 KubeSense 告警工具查询告警、规则、详情、历史、通知渠道和调查记录。还介绍经过验证的 `create-alert` 与 `validate-alert-json` 工具。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ kubesense-ai/ kubesense-mcp-skills --skill kubesense-alerts安装后在 Claude Code 中输入/kubesense-alerts确认已加载。
附带文件references/datadog-migration.mdreferences/import-json.md
详细介绍
KubeSense Alerts
两项不同的任务,别混淆:
- 读取告警——当前有哪些告警正在触发、哪些超出阈值、是否长期存在。纯 MCP 工具调用。
- 创建告警——使用
create-alertMCP 工具(经过验证,创建一条规则),或 导入 JSON(可在 UI 中审核,支持批量导入)。
路由
| 用户在询问…… | 执行此操作 |
|---|---|
| “现在有哪些告警正在触发?” | list-active-alerts |
| “有哪些告警规则/我创建过告警吗?” | list-alert-rules(对于 created_by,加上 get-current-user) |
| “这个告警触发了——哪里出问题了?” | 针对对应范围调用 get-alert-details,然后使用 kubesense-infra 查看变更和基础设施故障 |
| “这是反复触发还是新出现的?” | get-alert-history |
| “以前有人查明过这个问题的根因吗?” | find-investigation-for-alert |
| “创建一条在……时触发的告警”(一条规则,由 Agent 应用) | create-alert MCP 工具 |
| “给我……的告警 JSON”/多条规则/迁移 | 导入 JSON → references/import-json.md |
| “迁移这些 Datadog 监控器” | references/datadog-migration.md |
| “为什么触发了告警却没人收到通知?” | 先检查通知渠道的频率,再确认是否有维护时段覆盖 |
| “把这些规则放进列表/文件夹” | 只能在 UI 中分组——没有 MCP 接口,应如实说明,不要猜测 |
| 你手动编写了规则 JSON,想要检查 | 交给用户前先运行 validate-alert-json |
| “错误预算”“燃烧率”“是否达到了 99.9%” | 使用 kubesense-slo——燃烧率规则由 SLO 的 alert_types 生成,而不是手动编写 |
读取告警
| 工具 | 范围 |
|---|---|
list-active-alerts | 当前正在触发的原生存储中的时间序列,并与规则元数据关联。筛选条件:from_time/to_time、fingerprint、acknowledged、assignee、include_resolved。 |
list-alerts | 外部 Alertmanager——仅包含标签,不含规则配置。数据来源不同;除非明确需要查看 Alertmanager 状态或静默规则,否则使用 list-active-alerts。 |
list-alert-rules | 规则定义,包括已禁用和未触发的规则。按创建时间从新到旧排列。筛选条件:enabled、state、severity、query_type、search、created_by。 |
get-alert-details | 某条规则的完整配置(query_config、条件、阈值)以及其触发实例。调查时从这里开始。 |
get-alert-history | 触发/已解决状态变更,按时间从新到旧排列——用于判断问题是长期存在还是新出现。 |
find-investigation-for-alert | 最近一次已结束的 AI 调查及其根因。found=false 是正常情况,不代表错误。 |
list-notification-channels | 仅列出已启用的渠道:id、name、type。 |
检查手动编写的规则 JSON
每当你自行组装规则文档——导入 JSON、迁移后的 Datadog 监控器或编辑过的导出文件——都要在交给用户前通过 validate-alert-json 验证。该工具不会存储任何内容,并会一次性报告所有问题:
# valid=false findings=2
path rule message
/query_config/0/queryMode shape value must be one of 'builder', 'code'
/metric_query_label metric_query_label names query "A", but the rule's queries are labelled "B"
每个 path 都是指向待修复值的 JSON Pointer。重复验证,直到 valid=true。
它验证的是线缆文档——包含 query_config、
threshold_operator 和 frequency_type 的导出/导入格式。它不用于 create-alert 的参数;
该工具会验证自己的输入,并报告相同的问题。
重要
“我创建了哪些告警?”——调用
get-current-user,并将返回的**username**作为created_by传入。存储的创建者字段是用户名;电子邮件永远无法匹配,而且这两个值经常不同。
指纹用于标识某条规则的一个触发时间序列(一个命名空间/Pod/工作负载)。
传入指纹可将 get-alert-details/get-alert-history 的结果限定为该实例;省略则查询整条规则。
警报可以离开「正在触发」状态,而无需恢复
有两个表示人为操作的动词用于处于触发状态的序列,它们的含义不同:
| 表示 | 是否仍处于「正在触发」状态 | 通知 | |
|---|---|---|---|
| 确认 | 「我正在处理」 | 是 | 双重抑制 — 见下文 |
| 解决 | 「已处理」 | 否 | 仅针对此次违规进行抑制 |
解决操作会关闭当前违规;序列一旦不再违规,引擎就会清除标记,因此之后真正再次违规时会照常发送通知。这不是静音。
确认操作通过两种独立机制抑制通知:最长 7 天的 Alertmanager 静默,以及引擎端检查,在数据库标记存在时完全跳过发送。**该标记没有过期时间。**绝不要告诉别人通知会在一周后自动恢复——除非警报解决、状态反复变化,或有人取消确认,否则通知不会恢复。
重要
MCP 输出中的任何内容都无法将这两种情况与真正恢复区分开来。手动解决的序列只会新增一个
ends_at,然后从list-active-alerts中消失,这与已恢复的序列完全一样。因此,切勿仅凭include_resolved就断定「它在 14:02 恢复了」——应说警报已关闭;如果用户询问已知故障为何变成正常状态,应引导他们查看警报自己的页面,该页面可以区分这两种情况。
创建警报 — 选择哪种方式?
create-alert MCP 工具 | 导入 JSON | |
|---|---|---|
| 每次调用的规则数 | 一个 | 一个或多个(批量) |
| 字段名称 | fields/group_by_fields 会自动转换——先尝试目录标签,再尝试存储名称。where 则严格要求使用目录标签 | 必须完全正确,使用引擎自己的术语 |
| 验证 | 提前验证,并给出精确错误,便于重试 | 导入时由服务器验证 |
| 应用者 | Agent(写入工具,需要审批) | 用户,在 UI 中操作 |
| 最适合 | 用户想立即创建的单条规则 | 便于审核的输出、多条规则、迁移 |
单条规则优先使用 create-alert——它会根据引擎自己的验证器解析字段名称,因此不会生成引擎拒绝的名称。当用户要求提供「JSON」、想在创建前先审核,或要迁移多个监控项时,优先使用导入 JSON。
create-alert
{
"signal": "traces",
"name": "Checkout p95 latency high",
"description": "p95 above 500ms for 5 minutes",
"where": "service = checkout",
"value_operation": "p95",
"fields": [ { "field": "duration" } ],
"group_by_fields": [ { "field": "workload" } ],
"threshold_operator": "greater_than",
"threshold_value": 500000000,
"severity": "warning",
"notification_channels": [1],
"time_window": "5m",
"evaluation_interval": "1m"
}
signal:metrics|logs|traces。- metrics → 提供
promql。logs/traces → 提供where(search-logs 语法)+value_operation;若不是row_count,还需提供fields。 - 这里的
value_operation比查询工具支持的范围更窄:row_count、unique_count、avg、sum、min、max— 不支持百分位数。若要创建 p95 延迟规则,请使用导入 JSON。 - 必填项:
name、threshold_operator、threshold_value、notification_channels。 - 默认值:
severity=warning、threshold_frequency=at_least_once、evaluation_interval=1m、time_window=5m。 - 这里的
threshold_operator也接受above/below(导入 JSON 不接受)。构建规则前会先将它们规范化 —above会存储为greater_than,below会存储为less_than— 因此读取规则时会返回规范值,而不是你发送的值。若已知规范名称,请优先使用。
多个查询与公式
比率——错误率、占总量的比例、一个查询除以另一个查询——不再受导入路径限制。传入 queries 而不是扁平的单查询字段,并为最后一项提供 expression:
{
"signal": "traces",
"name": "Checkout 5xx rate above 5%",
"queries": [
{"label": "A", "where": "status_code LIKE \"5__\"", "value_operation": "row_count",
"group_by_fields": [{"field": "workload"}]},
{"label": "B", "where": "", "value_operation": "row_count",
"group_by_fields": [{"field": "workload"}]},
{"label": "C", "expression": "A / B * 100"}
],
"threshold_operator": "greater_than",
"threshold_value": 5,
"notification_channels": [1]
}
queries和扁平字段(promql、where、value_operation、fields、group_by_fields)互斥——传入queries,所有内容都放在其中。label默认按位置依次为A、B、C,且只能使用字母;最多 26 个查询。- 公式条目只能包含
expression,且只能引用排在它前面的查询。 - 每个非公式查询都针对规则唯一的
signal运行——一条规则不能混用日志与指标。 - 分组输入必须按相同字段分组。 引擎会按这些键匹配序列,因此两个输入若分组方式不同,其键就无法匹配。
create-alert会提前拒绝这类规则,并指出两种分组方式——你无法先创建规则再发现问题。 - 未分组的输入不受此限制,而且这是有意设计的。 单个未分组序列会广播到已分组序列,这正是“此工作负载占总量的比例”:将
A按workload分组,让B保持未分组,阈值设为A / B * 100。 - 通过导入 JSON引入同样的分组不匹配时,不会进行检查——没有任何东西会拒绝它,连接操作不会产生结果,而空结果会被视为正常。规则就这样悄无声息。这正是通过
create-alert构建多查询规则的理由。 - 阈值应用于公式。若有多个查询且没有公式,请在
threshold_query中指定要设阈值的查询。 - 在
queries中接受"where": ""——分母为“全部”正是其用途——而未加筛选的单查询规则则会被拒绝。
重要
where使用目录标签,且只能使用目录标签。 使用status_code,而不是return_code;使用instance,而不是pod_name。若填写存储列名,则会被拒绝:field "return_code" is a storage column; use the catalog label "status_code" instead这与下文所述的词汇正好相反;下文规定的是已存储和导入的规则——在那种情况下,
return_code正确,而service不正确。同一条规则会根据其进入引擎的方式采用两套词汇。fields和group_by_fields更宽容:create-alert会先尝试目录标签,再尝试存储名称,因此两者在此处都有效。where则不会进行转换。工具自身描述中的示例就有这个错误——它在
where中填写了return_code,会被同一工具背后的验证器拒绝。不要照抄。
此处仍无法使用百分位数:value_operation 没有 p95,因此 p95 延迟规则仍需通过导入 JSON 创建。
labels 会为规则及其触发的每条告警附加额外标签。这些标签用于路由,也会在 {{placeholders}} 中解析——见下文。
警告
先调用
list-notification-channels。notification_channels为必填项,且必须包含真实的通道 ID。不存在的 ID 会直接导致规则创建失败。如果没有任何通道,请告知用户必须在设置中创建通道——不要悄悄创建规则,因为它会触发告警,却无人收到通知。
这是一个写入工具。调用前,请明确说明你将要创建的内容。
遇到拒绝时
规则存储前会根据线协议约定进行检查,因此拒绝时会指出确切字段:
invalid alert: /query_config/0/queryMode: value must be one of 'builder', 'code'
每条发现都包含指向工具构建的规则的 JSON Pointer,以及相应的问题。修正后再次调用——这次往返比看起来更省事,也远比创建一条存储成功、随后却什么也不评估的规则划算。
两类失败的含义不同。invalid alert: … 表示需要由你修正。failed to create alert rule: … 表示服务器问题——应报告,而不是重试。
字段名称——不同的词汇表
重要
告警引擎接受的字段集与查询工具不同。MCP 查询目录标签(
type、instance、service、node)并非在此处全部有效。这里涉及三套词汇表:
- 查询工具(
analyze-logs、search-traces)——仅目录标签。- 告警分组字段/值字段——标签与存储名称的混合,且会严格验证。
- 告警筛选键——分组字段集合,外加额外的存储名称覆盖项。
日志——分组字段和值字段(19 个,精确列表)
instance workload namespace cluster pod container node
pod_name container_name level format host body_length
region app_version customer_identifier source
service env_type
请注意,两种写法都有效:pod 和 pod_name、container 和 container_name、node 和 host、instance。此处的严重性字段是 level,而不是查询工具中的 type。
service 和 env_type 最近才开始被接受(KUBE-2638)。日志目录从一开始就在“分组依据”下拉菜单中提供了这两项,但引擎却拒绝它们,因此选择任一项都会导致规则创建失败。如果遇到仍拒绝它们的安装版本,说明它早于此修复——请改为按 workload 分组。
日志筛选键 = 上述 19 项 加上 env、node_name 和 body。
说明
body是筛选键,不是维度。 系统接受raw_filters: {"body": ["timeout"]};但仍会拒绝将body用作分组字段或值字段,这是有意为之——按消息文本分组会导致每个不同的行都生成一个序列,而且没有可聚合的内容。body_length是数值字段,两者并不相同。根据其存储方式,会产生两种影响。筛选
body会强制使用原始表(汇总表没有此列),因此每次评估都需要进行完整扫描——在繁忙的租户中将其用于 24h 时间窗口前,值得明确说明这一点。此外,针对body的裸ILIKE会被重写为令牌搜索,因为在 SQL 中它会进行精确匹配,无法匹配任何实际日志行。令牌搜索不区分大小写,并按非字母数字字符拆分,因此hasAnyTokens出现“误报”是索引固有的行为,并非缺陷——请预期会出现这种情况,不要将其报告为告警错误。不接受
pattern_id:它只存在于汇总表中,因此使用它的规则会在查询回退到原始表时失效。
跟踪——分组字段和值字段(40 个,精确列表)
28 个目录标签:
status protocol source role status_code namespace method
workload container region app_version resource server client
server_namespace client_namespace node operation_name
partner_cluster customer_identifier duration duration_quantile
duration_avg pod instance cluster return_code app_service
……再加上 12 个存储名称,这才是 Web 应用实际为跟踪分组保存的名称:
container_name pod_name node_name kind subtype protocol_type
clustered_resource perspective_namespace perspective_workload
env_type app_db issue_reason
过去,分组只接受第一个列表,因此 UI 提供的 27 个可分组跟踪字段中有 12 个在保存时会遭拒——这也是 KUBE-2638 修复的内容,也解释了为什么现在接受 issue_reason,而旧说明中却称其不接受。
跟踪筛选键 = 上述 40 项 加上 is_external、app_name、partner_namespace、partner_workload。
因此,对于跟踪,目录名称和存储名称都可用作筛选键和分组字段(status_code 和 return_code、resource 和 clustered_resource、method 和 subtype)。
警告
跟踪不接受
service——请使用app_service。 查询工具首选的标签在告警引擎的跟踪侧不存在,拒绝消息也明确说明了这一点。(日志则相反:它们接受service。)对于日志,node_name仅可用于筛选——作为维度时,该列名为host。
标记为 is_attribute: true 的字段会跳过验证;筛选键为空、为 advanced_query 或以 @ 开头时也会跳过验证。
错误字段名会发生什么
导入时,规则会被拒绝,并返回 400 和针对每个字段的消息:
query A (traces): group-by field "issue_reason" is not accepted by the alert engine
and would freeze the rule — not supported by the alert engine
设置这道防护,是为了避免它所阻止的评估时行为:引擎无法解析的名称会导致每次评估都出错,随后引擎会保留规则的当前状态。新规则会悄无声息地永远不触发;已经触发的规则则会冻结——永远无法恢复,而且修改其阈值也没有效果,因为查询会在检查阈值之前出错。
导入时的允许列表是手动维护的引擎允许列表副本,没有自动漂移检查,因此请注意,验证通过但始终不触发的规则可能遇到了这个问题,并在条件图表中确认。
会悄然改变规则的陷阱
| 陷阱 | 后果 |
|---|---|
groupBy 条目缺少 field、type 或 is_attribute | 整个 groupBy 会被清空——规则会作为一个全局序列触发,而不是按标签分别触发 |
数值型 value_operation(例如 p95)缺少或包含错误的 fields | 会悄然降级为 row_count——延迟规则变成计数规则 |
数值运算的 fields[].type 不完全等于 "float" | 同样会降级 |
unit: "ns" / "percent" / "short" | 都是无效值——会悄然变成 auto。请使用 nanoseconds、percentage、number |
仅设置 frequency_type: "always" | 会悄然降级为 at_least_once——还必须发送 threshold_frequency: "always" |
单规则导入时设置 notification_channel_ids: [] | 编辑器要求至少有 1 个频道;用户无法点击创建 |
手动编写的 unified_filter 块 | 导入时绝不会读取——会悄然丢弃 |
advanced_query 与其他 raw_filters 键同时出现 | advanced_query 具有排他性;其他所有筛选键都会被丢弃 |
query_config 条目中包含 label 键 | 会被忽略——标签按位置绑定(索引 0 → A,1 → B) |
路由到 pagerduty / jsm / datadog_oncall 的规则设置 send_resolved: false | 会被拒绝并发出警告。 已恢复的负载会在这些系统中关闭事件,因此抑制它会导致事件永远保持打开状态 |
| 删除规则后,用相同名称重新创建规则来“恢复”它 | 删除是软删除——旧规则会保留其历史记录,并继续保持删除状态。你会得到一个没有过往事件的新规则 |
请务必告知用户在点击创建之前,先在导入编辑器的条件图表中确认各项值。
通知行为
触发中的规则实际多久通知一次,主要由频道而不是规则决定。
| 设置 | 所在位置 | 作用 |
|---|---|---|
group_interval | 频道 | Alertmanager 多快会重新检查内容发生变化的组。默认值较短,而且分组规则的内容会随着序列的出现和消失而不断变化——通常,这才是“为什么几乎每次评估都会通知?”的答案,而不是 repeat_interval。 |
repeat_interval | 频道 | 内容未变化的触发中组多久重新通知一次。只有在 group_interval 不再触发后,它才会起作用。通常以小时计。 |
send_resolved | 频道 | 频道是否会通知恢复情况。 |
send_resolved | 规则 | 按规则覆盖频道设置。不设置则继承——在此功能出现之前,所有规则都是如此。 |
有意不开放 group_wait 和 group_by。设置错误会导致你收不到提醒,而不只是减少提醒次数。
规则上的 send_resolved: false
适用于仅需触发并在恢复时保持静默的信息性规则,例如“出现了新的账本”“部署已开始”,且无需为其单独创建频道。关于哪些情况下会拒绝该设置,请参阅“陷阱”表。
send_count 不是通知次数
每次实际发送的评估都会递增一次,因此它大致等于触发持续时间 ÷ evaluation_interval。在 1m 规则上的两天告警会显示约 3000。绝不要把它说成“向某人发送了 3000 次通知”——实际通知到人的次数受上文所述渠道频率限制。
还有两点会让它无法准确衡量持续时间:
- **已确认的评估不会计数。**抑制检查会在发送前返回,而递增计数器的 upsert 是发送流程的一部分——因此只要有人保持确认状态,这个数字就会停滞。
- **它不是按触发事件分别计数。**该行以指纹为键,重新触发会重置
starts_at,但会累加send_count。一个打开又关闭过五次的序列,计数会累加这五次的总和。
确认
确认会停止针对该次触发实例的通知,而告警仍会显示为 Firing Now——它表示“我正在处理”,而不是“问题已经结束”。取消确认会使静默失效。
它通过两种彼此独立的机制进行抑制,且只有一种有截止时间:最长 7 天的 Alertmanager 静默,以及引擎端的检查——只要数据库中的 acknowledged 标记处于设置状态,就会直接跳过发送。此标记永不过期。
因此,不要告诉任何人分页通知会在一周后自动恢复。只有在序列解决、状态反复变化或有人取消确认时,通知才会恢复——下次实际触发时的 upsert 会清除 acknowledged,以及该次已结束事件的其他信息。
Trace 延迟阈值的单位是纳秒
告警引擎读取的 Trace duration 单位是纳秒,汇总百分位数也一样。
| 用户描述 | threshold_value |
|---|---|
| 100ms | 100000000 |
| 250ms | 250000000 |
| 500ms | 500000000 |
| 1s | 1000000000 |
ns = ms × 1_000_000。设置 "unit": "nanoseconds"。
说明
这与查询工具不同,后者的
durationWHERE 筛选条件以毫秒表示。告警:纳秒。查询:毫秒。参见 kubesense-traces。产品自带的
type-tracing起始模板使用threshold: 500,描述中写着“ms”——这实际表示 500 纳秒。不要照搬。
文本和模式筛选器
要匹配单个正文内容,请直接按 body 筛选——raw_filters: {"body": ["timeout"]}——并查看日志字段列表下方的说明,了解其代价和匹配方式。
对于简单前缀运算符无法表达的条件——例如对两个短语进行 OR 匹配、混合匹配正文文本与另一个字段,或匹配状态码类别——unified_filter 无法通过导入使用,唯一可行的方法是使用保留键 advanced_query 存放 WHERE 字符串:
"raw_filters": {
"advanced_query": ["body SUBSTR_ILIKE \"timeout\" OR body SUBSTR_ILIKE \"connection refused\""]
}
状态码类别也是如此——return_code LIKE "5__"(_ = 一个字符:4__ = 4xx,40_ = 40x)。请记住,advanced_query 会替换所有其他筛选器键,因此要将所有条件合并到同一个字符串中。
raw_filters 的值也支持前缀运算符,可用于简单情况:
| 前缀 | 操作 | 示例 |
|---|---|---|
| 无 | IN | {"level": ["ERROR"]} |
- | NOT IN | {"return_code": ["-200"]} |
> < >= <= | 比较 | {"duration": [">500000000"]} |
由于这些筛选器格式较为繁琐,而且筛选器绑定失败时会静默无效(此时规则会匹配所有内容,而非什么都不匹配),可靠的做法是:在 Explorer 的高级查询编辑器中构建条件,在告警编辑器中添加该条件,在条件图表上验证,然后导出。
名称或描述中的占位符
规则名称或描述中的 {{...}} 会按每个触发序列展开,因此一条规则会为每个分组生成一个标题各不相同的告警。占位符有两个命名空间。
规则自身的标签——其分组键以及携带的任何 labels。每个占位符按以下顺序解析:
-
标签键本身。 精确匹配始终优先。
-
UI 标签别名,且仅当该列位于此告警的标签中时才使用。Group By 下拉菜单中有 16 个字段,它们在界面中显示为一个名称,存储时使用另一个名称:
service→app_service domain→cluster resource→clustered_resource container→container_name node→host instance→pod_name type→level status_code→return_code method→subtype protocol→protocol_type role→kind reason→issue_reason primary_workload→perspective_workload primary_namespace→perspective_namespace associate_workload→partner_workload associate_namespace→partner_namespace规则 1 可确保解析没有歧义:
service是日志自身的service和 Trace 的app_service对应的 UI 标签,每条规则都会根据自身的列进行解析。别名不会凭空生成值——如果两者都未用于分组,{{domain}}就会保持原样,这样拼写错误会显现出来,而不会被悄悄渲染为空。 -
与属性同名。 按属性
topic分组时,{{topic}}会解析为该属性,即使存储的键是@topic。
{{@topic}} 也可以使用;当存在同名的普通标签时,应使用这种形式:如果 topic 和 @topic 都存在,{{topic}} 会返回列(规则 1),只有 {{@topic}} 会返回属性。经过消歧的分组键也会在占位符中保留其后缀——同一属性按类型或位置分组两次时,分别使用 {{status:float}} 和 {{status#0}}。
告警自身的事实信息使用保留的 Alert. 前缀:
{{Alert.status}} {{Alert.value}} {{Alert.threshold}} {{Alert.thresholdOperator}}
{{Alert.severity}} {{Alert.timeWindow}} {{Alert.frequency}}
{{Alert.startedAt}} {{Alert.startsAt}} {{Alert.endsAt}}
{{Alert.evaluatedFrom}} {{Alert.evaluatedTo}}
- 前缀不可省略,也不是装饰。裸写的
{{status}}会优先解析规则的标签status,因此对于按名为status的属性分组的规则,它显示的是“firing”,而不是属性值。这个命名空间消除了冲突——任何分组都无法生成以Alert.开头的键。 {{Alert.status}}会渲染为firing、resolved或no_data——这些是小写标记,不是显示文本。startedAt/endsAt界定事件持续时间;evaluatedFrom/evaluatedTo界定查询时间范围。 如果规则在 5 分钟的窗口内持续触发 3 小时,事件持续时间就是 3 小时,窗口则是 5 分钟。因此,使用事件持续时间构建的“查看是什么触发了此告警”链接,会展示 3 小时的数据来解释 5 分钟内的情况。请使用evaluated*构建链接。- 缺失的读数会渲染为
no_value。 对于未测得任何值的序列,{{Alert.value}}是唯一会显示标记、而不是保持原样的事实信息,因为作者会将它放入告警名称中,而原样发送{{Alert.value}}会直接出现在 Slack 消息里。它不会被渲染为0.00,因为那是有效的测量值。 - 缺失的时间会保持原样。 对于正在触发的告警,
{{Alert.endsAt}}会渲染为它本身,而不是0001-01-01;当窗口未知时,evaluatedFrom/evaluatedTo也一样。
维护窗口
采用 Datadog 风格的计划停机:在一段时间内,某个范围内的窗口会静默告警通知;对于部署了 alert_rule_engine#71 的版本,也会同时静默匹配的工作流触发器,包括触发和恢复两种情况。遥测数据仍会传入,规则仍会评估,告警仍会触发和恢复,历史记录仍会保存,SLO 预算仍会消耗。
理解这一点很重要:被静默的告警在 list-active-alerts 和 get-alert-history 中看起来完全正常。如果用户问为什么触发的告警没有通知任何人,维护窗口可能是原因之一,而没有 MCP 工具能查询维护窗口——请如实说明,并引导用户前往 Alerts → Maintenance Windows,而不是根据告警自身的数据猜测。
- 范围可以是规则 ID 和/或标签匹配器,采用 Alertmanager 的语义:正则表达式必须匹配整个字符串,不存在的标签按空值处理。
- 除非明确设置
scope_all,否则空范围不会静默任何内容——空白表单无法屏蔽整个系统。 - 计划可以是单次、每日或每周,按墙上时钟时间和 IANA 时区存储,因此“每晚 01:00”在夏令时变更后仍是 01:00。
- 抑制通过 Alertmanager 的静默规则实现,而不是让引擎停止运行。停止运行会触发
resolve_timeout,导致误报一切正常。
导入 JSON
有关完整的顶层架构、query_config 格式、所有枚举、批量导入,以及指标/日志/链路/公式规则的已验证可用示例,请参阅
references/import-json.md。
要点:
- 使用扁平字段(
threshold_operator、threshold_value)和普通时长字符串("5m",而不是*_prometheus_format)——包括breach_counting_window,这是导入时读取的字段名;POST 请求体和导出内容使用的是breach_counting_window_prometheus_format。请同时发送这两个字段,绝不能省略:单独使用_prometheus_format字段名会被忽略,规则会静默地采用5 分钟。这适用于always和more_than_once。 - 一条规则对应一个 JSON 对象。多条规则对应一个 JSON 数组,可通过批量导入并进行试运行审核。绝不要为每条规则分别输出代码片段。
- 导入时会忽略
enabled和query_type——服务器会将规则硬编码为启用状态,并根据第一个查询的selectedMode推导类型。 - 通过 Alerts → Alert Rules → Import JSON → 审核 → Create 应用。在用户确认之前,不会写入任何内容。
绝不要声称告警已通过导入流程创建——需要由用户导入并确认。
先发现,再操作
绝不要杜撰指标名称、字段或频道 ID。
| 你需要 | 调用 |
|---|---|
| 指标名称 | get-available-metrics → get-metric-labels |
| 日志/链路字段名称和值 | get-trace-or-log-fields |
| 频道 ID | list-notification-channels |
| 你自己的用户名 | get-current-user |
如果遇到不熟悉的规则格式,请让用户导出一条类似的现有规则并进行修改——这样可以确保 query_config 格式有效。
即使没有 MCP,你仍可根据上述允许列表生成日志/链路规则(这些是规范来源,不是猜测);但不得杜撰 PromQL 指标名称——这些名称因集群而异。请询问用户,或让他们导出一条参考规则。
规则
- 发出规则前,先发现每个指标、字段和频道 ID。
- 使用告警引擎的字段列表,而不是查询工具的目录标签。对于 trace,使用
level而不是type;使用app_service而不是service。 - 首先调用
list-notification-channels。绝不编造 ID;[]会阻止单条规则导入。 - Trace 延迟阈值使用纳秒,
unit: "nanoseconds"。 - 每个
groupBy条目都要包含全部三个键,否则分组会被静默丢弃。 - 数值型
value_operation需要fields的type: "float",否则会退化为row_count。 unit必须是有效的格式化器值——nanoseconds、milliseconds、percentage、bytes、CPU、number、raw。- 文本/类别筛选条件必须放在
raw_filters.advanced_query中,绝不能放在unified_filter中——advanced_query会取代所有其他筛选键。 - 查询标签是按位置对应的;
metric_query_label用于指定要设置阈值的查询 (单个查询 →A;公式 → 公式的标签)。 - 一条规则 → 对象;多条规则 → 一个数组。无论哪种情况,都只用一个代码块。
- 只有当指标消失本身就是事件(仪表盘/心跳)时,才使用
no_data_state: "firing"。计数/速率/变化规则绝不能使用——健康时间窗口会返回空结果,而不是 0,因此在数值为 0 时使用firing会误触发。使用normal。 more_than_once需要设置breaches_count(≥ 2);always也需要设置threshold_frequency。这三种频率都会读取breach_counting_window—— 对于more_than_once,在该时间窗口内统计违规次数;对于always,检查条件在该时间窗口内是否持续成立;对于at_least_once,在该时间窗口内检查是否解除。若未设置该值,引擎会回退到time_window,但导入根本不会执行到这一步:编辑器会将空字段默认设为5 分钟。请传入该值。name中的{{field}}占位符会根据每个触发序列,解析为一个分组键或规则标签,例如按workload分组 →"High latency {{workload}}"。找不到匹配项的占位符会保持原样,这可以帮助你发现拼写错误。告警自身的属性需要加上Alert.前缀——使用{{Alert.value}},而不是{{value}}。- 提醒用户在创建前查看条件图表;除非
create-alert确实返回了 ID,否则绝不要声称规则已创建。