背景:为什么要做
在多数团队的告警通知链路里,飞书群是最常用的触达入口之一。但实际使用中经常遇到两个问题:
- 群机器人消息容易被刷屏淹没,高优先级告警难以第一时间触达具体责任人。
- 告警平台输出的是"事件",而飞书机器人要求的是"消息结构",需要一层转换与路由。
本最佳实践给出一套轻量、易维护的实现方式:
- 观测云产生告警后,通过 Webhook 推送到 DataFlux Func。
- Func 将告警事件转换为飞书群机器人 Webhook 的消息格式,并在消息中插入
@人员标签,实现精准提醒。
目标效果:
- 告警触达飞书群
- 支持
@单人/@多人/@所有人 - 支持按监控器、维度或告警等级做人员路由扩展
方案:怎么做
链路如下:

核心约定:在观测云告警模板中增加一行稳定可解析的字段,例如:
makefile
FEISHU_USER_IDS: ou_xxx,ou_yyy
Func 只做三件事:
- 解析
FEISHU_USER_IDS - 组装飞书群机器人所需 JSON
- POST 到飞书群机器人 Webhook
关键点:为什么能精准@
飞书群机器人如何实现 @人员
飞书群机器人文本消息中,通过插入以下标签即可渲染出真正的 @人员:
ini
<at user_id="ou_xxxxxxx"></at>
支持形式:
@单人:<at user_id="ou_xxx"></at>@多人:多个<at ...></at>用空格拼接@所有人:<at user_id="all"></at>
为什么需要 Func 做中转
观测云告警 Webhook 的事件结构与飞书机器人消息结构不同;Func 用于完成字段提取、内容清洗、去重/降噪(可选)与消息格式转换。
配置 1:观测云告警模板
建议在告警模板中保留关键字段,并单独增加一行 FEISHU_USER_IDS(便于稳定解析):
makefile
告警标题:{{ df_title }}
告警状态:{{ df_status }}
工作空间:{{ df_workspace_name }}
监控器:{{ df_monitor_name }}
检测项:{{ df_monitor_checker_name }}
维度标签:{{ df_dimension_tags }}
检测值:{{ df_monitor_checker_value }}
事件链接:{{ df_event_link }}
告警详情:
{{ df_message }}
FEISHU_USER_IDS: ou_xxx,ou_yyy
约定说明:
FEISHU_USER_IDS:必须单独一行。- 多个用户使用英文逗号分隔。
- 值为飞书用户
user_id(通常以ou_开头),不是姓名或工号。 - 不需要
@人时,可以不写这一行。 @所有人可约定为:FEISHU_USER_IDS: all。
配置 2:Func 转发与消息重组
环境变量
bash
FEISHU_WEBHOOK_URL=https://open.feishu.cn/open-apis/bot/v2/hook/xxxxx
如飞书机器人启用了签名校验,可在此基础上增加签名逻辑;本文以最常见的基础 Webhook 为主。
最小可用 Python 脚本(可直接用)
功能:接收观测云 Webhook -> 解析 FEISHU_USER_IDS -> 组装 @ 文本 -> 发送到飞书群机器人。
python
import json
import re
import requests
FEISHU_WEBHOOK_URL = DFF.ENV.get("FEISHU_WEBHOOK_URL", "")
USER_ID_RE = re.compile(
r'(?im)^[ \t]*FEISHU_USER_IDS\s*[:=]\s*([0-9A-Za-z,_-\s]+)\s*$'
)
def dedupe_keep_order(items):
seen = set()
result = []
for item in items:
if item and item not in seen:
seen.add(item)
result.append(item)
return result
def extract_user_ids_and_clean_message(message):
user_ids = []
def repl(match):
raw = match.group(1) or ""
for item in re.split(r"[,,、\s]+", raw.strip()):
item = item.strip()
if item:
user_ids.append(item)
return ""
cleaned = USER_ID_RE.sub(repl, message or "")
cleaned = re.sub(r"\n{3,}", "\n\n", cleaned).strip()
return dedupe_keep_order(user_ids), cleaned
def build_mentions(user_ids):
if not user_ids:
return ""
return " ".join([f'<at user_id="{user_id}"></at>' for user_id in user_ids])
def build_text(event, clean_message, user_ids):
lines = []
mentions = build_mentions(user_ids)
if mentions:
lines.append(mentions)
lines.extend([
f'告警标题:{event.get("df_title", "-")}',
f'告警状态:{event.get("df_status", "-")}',
f'工作空间:{event.get("df_workspace_name", "-")}',
f'监控器:{event.get("df_monitor_name", "-")}',
f'检测项:{event.get("df_monitor_checker_name", "-")}',
f'维度标签:{event.get("df_dimension_tags", "-")}',
f'检测值:{event.get("df_monitor_checker_value", "-")}',
])
if clean_message:
lines.append(f"告警详情:{clean_message}")
event_link = event.get("df_event_link")
if event_link:
lines.append(f"事件链接:{event_link}")
return "\n".join(lines)
def send_to_feishu_webhook(text):
payload = {
"msg_type": "text",
"content": {"text": text},
}
response = requests.post(
FEISHU_WEBHOOK_URL,
headers={"Content-Type": "application/json"},
data=json.dumps(payload, ensure_ascii=False).encode("utf-8"),
timeout=5,
)
response.raise_for_status()
return response.json()
@DFF.API("guance_to_feishu_webhook")
def guance_to_feishu_webhook(**event):
if not FEISHU_WEBHOOK_URL:
return 500, {"ok": False, "error": "missing FEISHU_WEBHOOK_URL"}
raw_message = event.get("df_message") or ""
user_ids, clean_message = extract_user_ids_and_clean_message(raw_message)
text = build_text(event, clean_message, user_ids)
result = send_to_feishu_webhook(text)
return 200, {"ok": True, "user_ids": user_ids, "result": result}
验证:按这几步一次打通
建议按以下顺序联调,减少排查成本:
- 飞书群创建并测试群机器人 Webhook。
- 使用
curl发送最小消息,确认@人生效。 - 在 Func 中配置
FEISHU_WEBHOOK_URL。 - 在观测云告警模板中加入
FEISHU_USER_IDS行。 - 部署 Func 脚本并触发一条测试告警。
手工测试飞书 Webhook(最小用例)
vbnet
curl -X POST "你的飞书Webhook地址" \
-H "Content-Type: application/json" \
-d '{
"msg_type": "text",
"content": {
"text": "<at user_id="ou_xxx"></at> 来自Webhook的测试消息"
}
}'
排查:最常见的 3 类问题
消息发送成功但未真正 @ 到人
user_id是否正确(是否为ou_...或all)<at user_id="xxx"></at>是否完整且未被转义- 被 @ 的用户是否在当前租户 / 是否在群内
告警到达但解析不到 FEISHU_USER_IDS
FEISHU_USER_IDS:是否单独一行- 是否混入中文符号、隐藏空格或额外换行
- 多用户分隔是否为英文逗号
Func 返回成功但飞书没收到
FEISHU_WEBHOOK_URL是否配置正确- Func 网络是否可访问飞书接口
- 飞书机器人是否启用了关键词 / 签名校验
收益:带来的改变
- 高优先级告警可精准触达责任人,降低"群消息淹没导致漏处理"的风险。
- 方案轻量、低侵入,只需告警模板约定 + Func 中转即可快速落地。
- 后续可扩展为:按监控器/环境/服务路由不同人员,或对接值班表做自动派发。
参考
- 观测云 Func Webhook 集成实践:func.guance.com/doc/practic...
- 飞书群机器人 Webhook:open.feishu.cn/document/cl...