点开告警链接,就该看到告警说的那个端口:一次 Grafana 告警深链实践

最近给 Grafana 的企微告警通知做深链:点开告警里的链接,直接落到这条告警说的那个端口的详情页,而不是列表页或某个看板首页。踩了一圈坑,记下来。

一、链接该指向哪:告警说的那个对象

原来的链接是 [查看 Grafana 告警页](http://<grafana>/alerting/list) —— 所有告警的列表页。点进去还得自己找刚才那条,找到也只是状态卡片,看指标还要再跳一次。等于把”找答案”的活儿又还给了用户。

一条真实告警长这样:

核心交换机:链路利用率过高 (>85%)
  端口:Ten-GigabitEthernet1/0/0/22
  描述:Ten-GigabitEthernet1/0/0/22 利用率 85.4%(按实测协商速率算)。已进拥塞区,随时开始丢包。

收到它,最想看的就一件事:22 口最近的利用率曲线。所以链接的落点应该是这个端口在它自己详情页里的样子,不是任何聚合页。

教训一:告警链接的落点 = 告警说的那个对象,不是列表页、不是看板首页。点开即答案。

二、第一个坑:“相关看板”不一定接得住

顺着”指个相关看板”的思路,我先换成现成的「核心交换机链路评估看板」。结果自己验证发现:点进去还是看不到 22 口。

翻定义才看出两个致命问题:

  1. 它的面板只画了上行口和堆叠口,不含业务下联口 —— 22 口根本不在里面。
  2. 它没有任何模板变量,端口全写死,URL 里带端口它也接收不了、过滤不了。

更清醒的是:现网 12 块看板,全都是写死端口的静态看板,一块模板变量都没有。

教训二:不是所有”相关看板”都能当深链目标——得先确认它包含这个对象、且有模板变量能选中。

三、深链成立缺两样东西

  1. 一个把单个端口画全的看板(利用率/流量/丢弃/错包/状态),且能用变量切端口;
  2. 一个能传参的链接:把告警里的端口名塞进看板 URL,打开自动选中。

第 2 件是 Grafana 的常规能力(?var-<变量>=<值>),但有个前提:值必须精确匹配。

关键细节:告警标签里的端口名、InfluxDB 里的端口名、看板变量里的端口名必须是同一个字符串,否则变量选不中、面板查出来是空的。动手前我先对齐三者口径,直接对 InfluxDB 拉真实取值:

from(bucket: "snmp_metrics")
  |> range(start: -30d)
  |> filter(fn: (r) => r._measurement == "if_table" and r._field == "oper_status")
  |> keep(columns: ["if_name"])
  |> group()
  |> distinct(column: "if_name")
  |> sort(columns: ["_value"])

26 个端口,格式就是 Ten-GigabitEthernet1/0/0/22,和告警标签逐字一致。

教训三:深链前提 = 同一个字符串。动手前先对齐告警标签、DB tag、看板变量三者的取值(distinct(tag) 拉真实值)。

四、造那块看板:单端口链路详情

新建「单端口链路详情 · 核心交换机」(uid core-port-detail):一个 if_name 模板变量 + 所有面板按它过滤。

变量候选值不从数据源手敲,而是直接 distinct(if_name) 动态拉 —— 端口增减自动跟上,也不会写错字。

8 个面板,全只统计选中的那一个口(|> filter(fn: (r) => r.if_name == "${if_name}")):

分区面板
端口概览端口状态 / 协商速率 / 当前利用率%(RX/TX 取大)
链路利用率利用率 RX/TX 趋势
流量与健康度流量 RX/TX / 丢弃率 / 错包·丢弃速率

默认时间 now-6h → now、1 分钟刷新。

最容易翻车:口径必须和告警一模一样

光有端口不够,数字得是同一个数。通知里写”利用率 85.4%“,点进去看板”当前利用率”要是别的数,深链就废了。

所以看板利用率算法我照着告警规则逐字抄:

利用率 % = bps × 8 ÷ 协商速率 × 100
协商速率按接口名前缀判断:FortyGigE → 40G / Ten-GigabitEthernet → 10G / 其余 → 1G

连”速率按接口名前缀推断”都保持一致。这样通知的百分比和看板的”当前利用率”是同一套算法,不会出现两个打架的数字。

注:从接口名推速率是近似口径(更严谨是读实测 if_high_speed)。但告警规则就是这么算的,看板就得跟它一致——深链的价值是”看到的和收到的是同一个数”,口径统一比”更准”更重要。

教训四:深链不只跳对地方,还得数字对得上——看板与告警的算法口径必须一致。

五、把端口塞进链接(守住两条红线)

[查看该端口链路详情](http://<grafana>/d/core-port-detail?var-if_name={{ .CommonLabels.if_name }})

渲染出来就是 …/d/core-port-detail?var-if_name=Ten-GigabitEthernet1/0/0/22,点开直接是 22 口的利用率/流量/丢弃率。

两条红线:

  1. 企微的”残缺链接吞消息”坑:markdown 一旦解析到不完整链接语法([ 没闭合、或 ]( 里 URL 为空),会把该行之后整条消息全吞掉。所以链接是无条件块的完整字符串,绝不用 {{ if }} 去拼。渲染后的 URL 只含 ? = / - .,无括号无空格,安全。
  2. URL 别画蛇添足:本来想加 &from=now-6h&to=now 指定时间,后来去掉——多一个 & 只徒增风险,时间交给看板默认值更干净。

教训五:深链 URL 越简单越好,且满足消息渠道对字符的全部约束。

六、验证:不看到数据不算完

“导入成功 ≠ 能用”。每个面板都实跑一遍查询确认真有数据:把 ${if_name} 换成真实端口、${__from/__to} 换成具体时间,逐条打 /api/ds/query。22 口 -6h 实测:

  • 8 个面板全有数据、0 报错;
  • 端口状态 UP、协商速率 10G、当前利用率 ≈ 26%,和链路对得上;
  • 变量查询实跑 → 26 个端口含 Ten-GigabitEthernet1/0/0/22;
  • contact point PUT 202,复核线上 message 末行已是这条深链。

看板双保险部署:API POST /api/dashboards/db 推一次立即生效,同时 JSON 放进 provisioning 目录扛重启。

教训六:交付前逐面板实跑验证——“看板能打开”和”看板有数据”是两码事。

七、踩坑清单

  1. 告警链接落点 = 告警说的那个对象,不是列表页/看板首页。点开即答案。
  2. “相关看板”未必接得住:先确认它包含这个对象、且有模板变量能选中。
  3. 深链 = 同一个字符串:告警标签、DB tag、看板变量三者取值逐字一致,动手前 distinct(tag) 对齐。
  4. 看板变量取值从数据源动态拉,别手敲。
  5. 数字要对得上:看板与告警计算口径(尤其分母/速率)必须一致。
  6. 企微红线:链接无条件块完整字符串;URL 别加多余 &。
  7. 逐面板实跑验证,“0 个空面板”才算完。

结语

真正决定成败的不是”怎么建看板""怎么写 URL”,而是一开始那个判断:这个链接到底把人带到哪。

“相关”很容易骗人——一块讲核心交换机链路的看板,对一条业务口告警来说看着相关,其实无关。判断标准就一句:收到告警的人,接下来想看的第一个东西是什么? 答案就是链接的落点。

指对了地方、指到正确的那个对象,链接才从”装饰”变成”入口”。