Skip to content

Webhook

通用 webhook 通道是兜底。当你要把告警推到 Ongrid 不原生支持的聊天平台、工单系统或内部转发(Microsoft Teams、Mattermost、Rocket Chat、OpsGenie、PagerDuty、你自家的路由),就用通用 webhook 指过去,告警流水线会把标准的 Ongrid 消息 JSON 推过去。

有专用通道就用专用通道

Slack / 飞书 / 钉钉 / 企微 / Telegram 的专用通道渲染更丰富的载荷(Slack attachments、签名)。只有没有专用通道时才用通用 webhook。

载荷

body 是标准的 notify.Message 形态,原样 JSON 序列化:

json
{
  "severity": "critical",
  "subject": "node-01 swap_high",
  "body": "swap_in_pages > 1000 for 5m",
  "source": "alert",
  "labels": {
    "rule": "swap_high",
    "incident_id": "1234",
    "device_id": "7",
    "host": "node-01"
  },
  "dedupe_key": "alert:swap_high:device=7",
  "occurred_at": "2026-05-30T14:02:35Z"
}

没有 envelope、没有 msgtype、没有扁平化。接收方拿到的就是告警流水线产出的字段。由 NewGenericWebhookSender 构造。

可选 HMAC 签名

填了 Secret 字段之后,每次请求都带 X-Ongrid-Signature 头:

text
X-Ongrid-Signature: sha256=<hex>

<hex>hex(HMAC-SHA256(secret, body)),对 POST 出去的确切字节计算。签名器是 signGenericWebhook

在接收侧校验

python
# Python receiver
import hmac, hashlib

def verify(secret, body_bytes, header):
    expected = "sha256=" + hmac.new(
        secret.encode(), body_bytes, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, header)
go
// Go receiver
func verify(secret string, body, header []byte) bool {
    mac := hmac.New(sha256.New, []byte(secret))
    mac.Write(body)
    expected := []byte("sha256=" + hex.EncodeToString(mac.Sum(nil)))
    return hmac.Equal(expected, header)
}

端点公网就必须校签

没签名的通用 webhook URL 谁知道谁就能投。签名头是唯一能证明"这条是 Ongrid 发的"的依据。

请求形态

属性取值
MethodPOST
Content-Typeapplication/json
User-Agentongrid-notify/1.0
Bodynotify.Message 的 JSON
签名头X-Ongrid-Signature: sha256=…(仅当有 secret)
超时单请求 http.Client 超时(默认 15s)

成功判定

Sender 把 HTTP 2xx(200–299)当成功。其他 —— 包括 3xx 跳转、4xx5xx —— 都算 unexpected status: …,降噪流水线里记为失败投递。响应 body 不解析;Ongrid 不关心你的转发回什么 JSON。

重试与降噪

重试语义归 告警流水线 管,不归 Sender 管。Sender 每次 Send(ctx, msg) 只 POST 一次。流水线决定:

  • 降噪窗口。 按规则配,默认 5 分钟。同一 dedupe key 每个窗口最多触发一次。
  • 持续触发重复通知。 默认 1 小时。incident 仍开着的话,过了这个窗口给通道再发一次,避免它埋在聊天历史里。
  • 恢复消息。 告警结束时发出。

Sender 的活是推字节。流水线的活是决定什么时候推。

传输失败不自动重试

如果 Sender POST 的那一刻接收方挂了,这条消息就丢了(作为投递错误进日志、出现在按通道的投递统计里)。流水线不排队也不晚些再试。理由:在恢复 3 分钟之后再投递一条 5 分钟前的旧告警,比缺一条更让人困惑。请用健壮的接收方,或者在 Ongrid 和不可靠下游之间自己加队列。

配置

  1. 起一个接受 POST + application/json 的 HTTP 端点。挑一个你会和 Ongrid 共享的强 secret。
  2. 在 Ongrid:Settings → Channels → New → Provider = webhook → Endpoint = 你的 URL → Secret = 共享 secret。
  3. Test。测试消息是合成的 notify.Message{Severity: "info", Subject: "Ongrid test", …}。在你的接收方日志里校验签名头。

配方

Microsoft Teams(incoming webhook)

Teams incoming webhook 接受的是另一种载荷形态(MessageCard)。最简单的路径是在 Ongrid 和 Teams 之间挂一个小转发:

python
# server.py - listens on /ongrid-to-teams
@app.post("/ongrid-to-teams")
def relay(msg: dict):
    teams_url = os.environ["TEAMS_WEBHOOK"]
    card = {
        "@type": "MessageCard",
        "@context": "https://schema.org/extensions",
        "themeColor": {"critical":"D92F2F","warning":"F2C037","info":"36A64F"}.get(msg["severity"], "6F7A87"),
        "title": msg["subject"],
        "text": msg["body"],
    }
    requests.post(teams_url, json=card)

Ongrid 这边通道指向 https://your-relay/ongrid-to-teams

PagerDuty Events API v2

同样的模式:写一个小转发,把 {severity, subject, body, dedupe_key} 翻译成 PagerDuty events.v2 载荷。PD 的 dedup_key 字段和 Ongrid 的 dedupe_key 一一对应,所以同一个 incident 在两边是同一条告警。

Splunk HEC / Elastic ingest

通道指向 HEC 端点,URL 里带 Splunk token。Splunk 接受标准 Ongrid JSON;按 severitylabels.rule 索引以便下游搜索。

字段参考

参见 Message 作为唯一真相源。稳定字段:

字段类型说明
severitystringcritical / warning / info
subjectstring规则名 + 目标 —— 一行。
bodystring多行细节。可能含换行。
sourcestringalert / test / 等。
labelsmap[string]stringruleincident_iddevice_id、自定义。
dedupe_keystringpipeline:rule:label-set。按身份稳定。
occurred_atRFC3339 stringUTC。告警 evaluator 触发的那一刻。

新字段只增不减 —— 接收方应忽略未知 key。

相关