> ## Documentation Index
> Fetch the complete documentation index at: https://docs.molesignal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 告警流水线

> 在开事件之前改写、补充告警事件，调整严重度或丢弃它，加上模型写的摘要或你自己系统的回答，并改写一条通知策略发出的内容。

**告警流水线** 在开事件之前处理告警事件。它的步骤可以改写事件的标题、调整严重度、增删标签和注解、写明受影响服务，或者丢弃告警事件、不开事件。[路由](https://docs.molesignal.com/zh-Hans/alerting/routing.md)和通知看到的都是流水线改完之后的事件。

告警事件有四种来源：

| 来源 | 事件 |
| - | - |
| **告警规则** | [告警规则](https://docs.molesignal.com/zh-Hans/alerting/rules.md)触发。 |
| **外部来源** | [告警来源](https://docs.molesignal.com/zh-Hans/alerting/sources.md)收到其他系统发来的告警。 |
| **拨测** | [拨测](https://docs.molesignal.com/zh-Hans/synthetics.md#告警事件)检查失败或没有结果。 |
| **无数据** | 规则开出[无数据事件](https://docs.molesignal.com/zh-Hans/alerting/rules.md#恢复条件与没有数据)。 |

手动开的事件在开出来之前不经过告警流水线。

流水线也可以在[通知之前](#通知之前)运行：处理事件的副本，只改一条通知策略发出的内容。

## 新建告警流水线

打开 **流水线**，选择 **新建流水线**，把 **执行模式** 设为 **告警事件**。**信号类型** 显示为 **告警事件**，设置里用[**执行顺序**](#执行顺序)代替调度。流程有三个节点：

| 节点 | 含义 |
| - | - |
| **告警事件** | 这条流水线处理哪些告警事件，参见[条件](#条件)。 |
| **处理步骤** | 各个步骤，按执行顺序排列，参见[步骤](#步骤)。 |
| **写回事件** | 按步骤改完的样子开事件。 |

**试运行** 在保存前让一条样例告警事件走完各步骤。步骤把它看作告警规则即将开事件时的告警事件：`%source` 为 `rule`，`%event` 为 `opened`。修改 **样例事件** 可以试别的值，然后选择 **运行**。结果显示每个步骤之后的事件，或丢弃它的步骤。试运行不保存任何数据，也不调用任何外部服务：**AI 摘要** 和 **查询补充** 步骤在各自的注解里写入 `…`，**调用接口补充** 步骤把事件原样往下传，并标明 **试运行时不调用**。

有 `alerts.incidents.read` 权限时，**用一条最近的告警事件** 列出最近 7 天的最新 20 个事件。选中一个，它的事件填入 **样例事件**，步骤读到的规则和来源也是它的。这是事件存下来的样子，已经带着开事件时流水线的改动。

设置里的 **处理告警事件** 开关启用或停用这条流水线：停用的流水线让所有告警事件原样经过。选择 **创建流水线** 保存。保存的改动在 10 秒内对所有节点生效。

## 条件

选择 **告警事件** 节点，设置这条流水线处理哪些告警事件：

* **来源**：**告警规则**、**外部来源**、**拨测** 和 **无数据**。规则开出的无数据事件算作 **无数据**，不算 **告警规则**；拨测检查没有结果时开出的事件算作 **拨测**。
* **严重度**：**严重**、**错误**、**警告** 和 **提示**。
* **标签**：**添加标签条件** 添加一个标签和值。事件必须带着每个标签，且值完全相同。
* **时间**：**任何时间**，或 **只在这些时段**、**只在这些时段以外**，按一个时区填每周的几段时间，按事件开出来的时刻判断。例如只在夜里 ETL 跑的那两小时丢掉某一类告警。

它们上方的 **运行时机** 决定流水线何时运行：默认 **开事件之前**，或 [**通知之前**](#通知之前)。

列表都不选就处理全部来源或全部严重度，没有任何条件的流水线处理所有告警事件。条件不命中的事件原样经过这条流水线。

## 执行顺序

告警流水线逐条运行，**执行顺序** 小的先跑，执行顺序相同时按名称排序。每条流水线拿到的是前面的流水线改完之后的事件，也按这个事件判断条件，因此一条流水线调高了严重度，就可能让事件命中后面某条流水线的条件。

## 步骤

**添加步骤** 提供其他流水线里的解析类和字段类步骤（包括 **查扩展表补充**）、**过滤事件**、**AI 摘要**、**调用接口补充**、**查询补充** 和 **自定义 VRL**，参见[处理步骤](https://docs.molesignal.com/zh-Hans/pipelines#处理步骤)。在告警流水线里，**按正则批量改名** 和 **只保留字段** 默认处理 `labels`。告警流水线不采样也不分流：流水线改成告警流水线时，已有的 **采样** 或 **数据分流** 步骤要先删除才能保存。

### 步骤看到的告警事件

步骤看到的告警事件是这样的 JSON：

```json theme={null}
{
  "summary": "Checkout error rate above 5%",
  "severity": "error",
  "labels": { "service": "checkout", "env": "prod", "host_name": "web-01" },
  "annotations": { "runbook": "https://wiki.example.com/checkout" },
  "affected_services": ["checkout"]
}
```

| 字段 | 内容 | 步骤可以写入的值 |
| - | - | - |
| `summary` | 事件的标题。 | 非空的文本。超过 512 个字符的部分会被截掉。 |
| `severity` | 事件的严重度。 | `info`、`warning`、`error` 或 `critical`，不区分大小写；`warn` 和 `crit` 分别读作 `warning` 和 `critical`。 |
| `labels` | 事件的标签。 | 值为文本的对象。数字和布尔值转为文本，`null` 删除该标签。 |
| `annotations` | 事件的注解。 | 同 `labels`。 |
| `affected_services` | 受影响服务的名称。 | 名称列表。重复的名称和空名称会被去掉。 |

步骤在这些字段之外添加的字段不会写进事件；步骤整个删掉的字段保持原值，要清空标签请写 `.labels = {}`。不符合这些规则的值（例如 `labels` 里套了对象）会让这条流水线出错，参见[处理结果](#处理结果)。

### 事件从哪里来

步骤从元数据读取告警事件的来历，这些值不会成为事件的字段。

| 元数据 | 值 |
| - | - |
| `%source` | `rule`、`external`、`synthetic` 或 `no_data`。 |
| `%rule_id` | 告警规则、告警来源或拨测检查的 ID。 |
| `%rule_name` | 告警规则、告警来源或拨测检查的名称。 |
| `%event` | 开事件之前为 `opened`；事件开着时来源再次触发，为 `severity_changed`，参见[严重度变化](#严重度变化)。 |

```ruby theme={null}
# 预发环境的告警最多按警告通知
if .labels.env == "staging" && (.severity == "critical" || .severity == "error") {
  .severity = "warning"
}

# 从扩展表 host_owner 查出主机所属的团队
owner = lookup("host_owner", .labels.host_name)
if is_object(owner) {
  .labels.team = owner.team
}

# 已知的误报不开事件
if %rule_name == "Disk inode usage" && .labels.mount == "/boot" {
  abort
}
```

第二步设置的 `team` 标签可以把事件交给这个团队，参见[分派顺序](https://docs.molesignal.com/zh-Hans/alerting/routing.md#分派顺序)。`lookup` 与 `geoip_lookup` 在告警流水线里和在其他 VRL 步骤里用法相同，参见[查扩展表与 IP 地址](https://docs.molesignal.com/zh-Hans/functions.md#查扩展表与-ip-地址)。

### AI 摘要

**AI 摘要** 步骤把前面步骤改完的告警事件连同 **提示词** 发给组织的模型，并把回答写进 **写入的注解** 指定的注解，默认为 `ai_summary`。提示词可以这样写：

```text theme={null}
用两句话为值班工程师总结这条告警：出了什么问题，先查什么。
```

* 只在开事件时调用一次模型，[严重度变化](#严重度变化)时不再调用。
* 使用最近更新、已启用且填了 API Key 的[模型服务](https://docs.molesignal.com/zh-Hans/agent#配置模型服务)及其 **默认模型**。回答不超过该模型服务的 **最大输出 Token**，未设置时不超过 512 个 token。
* 这一步会把告警的标题、严重度、标签、注解和受影响服务发给模型服务商。
* 调用计入组织的[每日 token 预算](https://docs.molesignal.com/zh-Hans/agent#用量与预算)，在按来源的用量里记作 **LLM 函数**。`[functions].llm_eval_enabled` 对它不起作用。
* 模型给不出回答时（没有配置模型服务、当天预算已用完或调用失败），这一步出错，整条流水线随之出错，其他步骤的改动也一并作废。希望其他改动无论如何都保留时，把 **AI 摘要** 步骤单独放进一条执行顺序靠后的流水线。

### 调用接口补充

**调用接口补充** 步骤把告警事件 POST 给组织的一个 [HTTP 连接器](https://docs.molesignal.com/zh-Hans/connectors.md#目标)，取回答里改动的内容。地址、凭据和出站防护都用这个连接器的：先解析主机名并固定连接到解析结果，拒绝云元数据地址，不跟随重定向。

请求体是前面步骤改完的事件，字段旁边带上事件的来源：

```json theme={null}
{
  "summary": "Checkout error rate above 5%",
  "severity": "error",
  "priority": null,
  "urgency": null,
  "labels": { "service": "checkout" },
  "annotations": {},
  "affected_services": ["checkout"],
  "metadata": { "rule_id": "…", "rule_name": "Checkout errors", "source": "rule", "event": "opened" }
}
```

* 回答的 JSON 对象里只取 `summary`、`severity`、`priority`、`urgency`、`labels`、`annotations` 和 `affected_services`，规则同[步骤看到的告警事件](#步骤看到的告警事件)。`labels` 和 `annotations` 按键合并，`null` 删除这个键，所以服务只需回答它要添加的内容。空回答什么都不改。
* 调用限时 5 秒，只在开事件时调用一次，[严重度变化](#严重度变化)时不再调用。
* 调用失败时（超时、状态码不是 2xx、回答不是 JSON 对象或超过 1 MiB、字段不符合规则、连接器已停用或不存在），只算这一步没做：事件照这一步之前的样子往下走，后面的步骤照常运行，前面步骤的改动保留。[时间线](#处理结果)和[计数](#当天的计数)写明原因。

### 查询补充

**查询补充** 步骤运行一条带事件取值的查询，把结果写进注解：

```sql theme={null}
SELECT count(*) AS errors FROM app_logs WHERE level = 'error' AND host = '{{labels.host_name}}'
```

| 字段 | 含义 |
| - | - |
| **语言** | SQL 或 PromQL。PromQL 读指标流。 |
| **数据类型**、**数据流** | 查询读取的数据流。这里不能读 `_audit`：这一步运行时没有任何人的 `audit.read` 权限可用。 |
| **查询** | 一条查询，可以带占位符。 |
| **往回看（秒）** | 从开事件的时刻往前看多久。默认 300，最多 86,400。 |
| **行数** | 写进注解的行数。默认 5，最多 50。 |
| **写入的注解** | 结果写入哪个注解，默认 `query_result`。 |

占位符代表事件里的值：`{{labels.<key>}}`、`{{annotations.<key>}}`、`{{summary}}`、`{{severity}}`、`{{priority}}`、`{{urgency}}`、`{{rule_id}}`、`{{rule_name}}` 或 `{{source}}`。标签可能来自其他系统，所以占位符必须写在语句的字符串里、引号之内，值在那里才会被转义。写在别处时保存返回 `400`。

* 注解里一行结果一行文字：只有一个值时就是这个值，多个值时写成 `column=value, column=value`。最多 4,000 个字符。查询没有结果时不写这个注解。
* 查询限时 10 秒，只在开事件时运行一次。
* 查询失败，或事件缺少占位符要的值时，只算这一步没做，和[**调用接口补充**](#调用接口补充)一样。

## 处理结果

每条处理了事件的流水线，结果是以下三种之一：

| 结果 | 原因 | 影响 |
| - | - | - |
| **处理** | 各步骤都执行完了。 | 事件带着这些改动继续。 |
| **丢弃** | 某个步骤执行了 `abort`。 | 不开事件，后面的流水线也不再运行。 |
| **出错** | 某个步骤失败，或步骤改出的字段不符合[步骤看到的告警事件](#步骤看到的告警事件)中的规则。**调用接口补充** 或 **查询补充** 步骤失败也算在这里。 | 这条流水线的改动作废；只是上述两种步骤失败时，其他步骤的改动保留。事件交给下一条流水线，照常开事件。 |

事件的[时间线](https://docs.molesignal.com/zh-Hans/alerting/incidents.md#事件详情)里，每条改了内容或出了错的流水线各有一行：**经过流水线 Payments routing：严重度 error → critical，标签 +team=payments**，出错时写明原因。什么都没改的流水线不留记录，[严重度变化](#严重度变化)也不留。一行最多显示 40 处改动，其余只计数，过长的值在 200 个字符处截断。

一直在触发的规则每次评估都会再被丢弃一次。[规则列表](https://docs.molesignal.com/zh-Hans/alerting/rules.md#规则列表)里它的状态显示为 **被流水线丢弃**，API 中规则的 `last_state` 为 `{"kind": "dropped"}`。丢弃事件的流水线记下这次丢弃，它的 **概览** 写明最近一次丢弃来自哪条规则。被流水线丢弃的外部告警在告警来源的[**最近收到**](https://docs.molesignal.com/zh-Hans/alerting/sources.md#最近收到)里显示为 **忽略**，旁边写明丢弃它的流水线和步骤。

## 严重度变化

事件开着时，告警规则每次再触发、外部来源每次再发来这条告警，或拨测检查的状态每次变化，告警流水线都会重新决定它的严重度：

* 按开事件时的方式重新构造告警事件，严重度取来源现在报的值，交给条件命中的流水线处理，但跳过其中的 **AI 摘要**、**调用接口补充** 和 **查询补充** 步骤；`%event` 为 `severity_changed`。
* 只取步骤最后定下的严重度，与事件当前的严重度不同时，事件改用它。标题、标签、注解和受影响服务保持开事件时定下的样子。
* 某条流水线这时丢弃或出错，什么都不改变：事件照样开着，下一条流水线照常运行。

因此，调低预发环境告警严重度的步骤，在规则之后报出更高的严重度时依然生效。已确认的事件保持原来的严重度，被手动设置过严重度的事件也保持不变。

## 通知之前

在 **告警事件** 节点把 **运行时机** 设为 **通知之前**，流水线就在[通知策略](https://docs.molesignal.com/zh-Hans/notification-channels)发送告警通知之前运行：处理事件的副本，每条适用的策略各跑一次，策略每次发送都会经过，包括它后续的步骤和升级。可以用它给短信策略缩短标题、给某个团队的 Webhook 加标签，或者让一条策略在夜里不发，而事件本身不变。

* **通知策略** 选择这条流水线针对哪些策略，一个都不选表示告警事件的所有通知策略。这时策略已经按进来时的事件匹配过了。
* 其他条件照常，按通知的事件判断：时间是事件发生的时刻，**来源** 多出 **手动开的事件**。
* 步骤只在 MoleSignal 内部运行。**AI 摘要**、**调用接口补充** 和 **查询补充** 只在开事件时运行，这里带着它们保存会返回 `400`。
* 流程以 **写进通知** 结束。策略发出步骤留下的标题、严重度、优先级、紧急度、标签、注解和服务：[模板](https://docs.molesignal.com/zh-Hans/notification-channels#模板变量)、Webhook 的请求体和默认文字里都一样。通知到哪些人仍按进来时的事件计算。
* 步骤执行 `abort` 时，这条策略不发。投递记录里留下一条 **已跳过**，用工作区的默认语言写明是哪条流水线的哪个步骤（`error_code` 为 `dropped_by_pipeline`），事件的时间线也会写明。这不算失败：这条策略不会重试，它的确认超时升级也不再继续。
* 流水线出错时它的改动作废，通知照进来时的样子往下走。出错记在[计数](#当天的计数)里，不进时间线。

除 `%rule_id`、`%rule_name` 和 `%source` 外，步骤还能读 `%policy_id` 和 `%policy_name`，`%event` 为 `triggered`、`escalated`、`acknowledged` 或 `resolved`。`%rule_name` 是规则的名称，不是规则开出的事件则是事件标题。**试运行** 用的样例值是 `triggered` 和 `On-call alerts`。

```ruby theme={null}
# 预发环境的值班告警只发严重的
if %policy_name == "On-call alerts" && .labels.env == "staging" && .severity != "critical" {
  abort
}
```

## 当天的计数

告警流水线没有运行，因此没有运行历史，**更多 → 回填** 对它也不可用。它改为统计当天（UTC）的处理情况：

* 列表里启用中的告警流水线 **状态** 显示为 **等待告警事件**，**最近运行** 列显示计数，例如 **今天：处理 41 · 丢弃 3 · 出错 0**。
* 流水线 **概览** 上的 **处理**、**丢弃** 和 **出错** 显示同样的计数。**丢弃** 下方写明最近一次丢弃来自哪条规则或哪个来源、发生在什么时候，**出错** 下方显示最近一次出错的原因。

计数在 UTC 零点归零。条件不命中的事件和[严重度变化](#严重度变化)时的重新处理都不计数。API 在 `alert_record` 中返回这些计数，参见[管理流水线](https://docs.molesignal.com/zh-Hans/api/intake/scheduled-pipelines.md#查看)。

## 限制

| 限制 | 值 |
| - | - |
| 一条告警流水线的步骤数 | 20 |
| **AI 摘要** 步骤的提示词 | 8 KiB |
| 注解名称 | 255 字节 |
| **调用接口补充** 步骤的回答 | 1 MiB，5 秒内 |
| **查询补充** 步骤的语句 | 8 KiB |
| **查询补充** 步骤的行数 | 50 行，10 秒内 |
| **查询补充** 步骤写入的文字 | 4,000 个字符 |

## 通过 API 创建

告警流水线和其他流水线一样保存，把 `function_steps.mode` 设为 `alert`，数据流与调度留空：

```bash theme={null}
curl -X POST http://localhost:5080/api/v1/scheduled_pipelines \
  -H "authorization: Bearer $MS_TOKEN" \
  -H 'content-type: application/json' \
  -d '{
    "name": "staging-alerts",
    "source_stream": "",
    "target_stream": "",
    "cron": "",
    "enabled": true,
    "function_steps": {
      "mode": "alert",
      "alert": {
        "sources": ["rule", "external"],
        "severities": [],
        "labels": { "env": "staging" },
        "order": 10
      },
      "steps": [
        { "transform_name": "cap-severity", "kind": "vrl",
          "script": "if .severity == \"critical\" { .severity = \"warning\" }" },
        { "transform_name": "summary", "kind": "ai_summary",
          "prompt": "用两句话为值班工程师总结这条告警。",
          "annotation": "ai_summary" }
      ]
    }
  }'
```

在通知之前运行的流水线把 `alert.stage` 设为 `notify`，可以用 `alert.policies` 点名策略：

```json theme={null}
{
  "mode": "alert",
  "alert": { "stage": "notify", "policies": ["<policy id>"], "labels": { "env": "staging" }, "order": 10 },
  "steps": [
    { "transform_name": "quiet", "kind": "vrl", "script": "if .severity != \"critical\" { abort }" }
  ]
}
```

全部字段参见[创建流水线](https://docs.molesignal.com/zh-Hans/api/intake/create-pipeline.md)。告警流水线使用与其他流水线相同的[权限](https://docs.molesignal.com/zh-Hans/pipelines#权限)。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.