多渠道通知网关服务,支持飞书和 Telegram。开发规范和提交规范见 AGENTS.md。
- 统一 API 接口,通过
channel参数切换通知渠道 - 支持飞书卡片消息
- 支持 Telegram Bot
- Grafana 13 统一告警集成
- 内置消息队列与自动限频重试
go build -o notify .复制环境变量示例并填入实际值:
cp .env.example .env使用 direnv 自动加载(推荐):
cp .env.example .envrc
vim .envrc # 填入实际值
direnv allow或手动加载:
source .env./notify镜像由 CI 自动构建并推送到 Docker Hub:
docker run -p 8000:8000 \
-e APP_FEISHU_ID=your_app_id \
-e APP_FEISHU_SECRET=your_app_secret \
-e APP_TELEGRAM_BOT_TOKEN=your_bot_token \
your_username/notify:latestPOST /api/messages
Content-Type: application/json
{
"channel": "feishu",
"target": "oc_xxx",
"params": {
"title": "消息标题",
"color": "Blue",
"content": "**Markdown** 内容",
"note": "备注信息",
"url": "https://example.com"
}
}
参数说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| channel | string | 是 | 通道类型:feishu / telegram,大小写不敏感,例如 Feishu、Telegram。不接受 Lark。 |
| target | string | 是 | 接收目标。飞书为 chat_id;Telegram 为 chat_id 或 chat_id:thread_id(支持 Topic)。 |
| params.title | string | 否 | 消息标题 |
| params.color | string | 否 | 标题颜色:Blue/Green/Orange/Grey/Red/Purple (Telegram 消息忽略此字段) |
| params.content | string | 否 | 消息内容(飞书支持 Markdown;Telegram 按纯文本转义) |
| params.note | string | 否 | 备注 |
| params.url | string | 否 | 跳转链接 |
接口返回成功仅表示请求已交给异步发送队列,不表示下游平台已经完成投递;最终结果以服务日志为准。
直接透传对应平台的原始消息结构,用于发送更复杂的卡片或特殊消息。
POST /api/messages/raw
Content-Type: application/json
{
"channel": "feishu",
"target": "oc_xxx",
"message": {
"config": { "wide_screen_mode": true },
"header": { ... },
"elements": [ ... ]
}
}
支持直接将 Grafana Webhook 指向此接口。
POST /api/webhooks/grafana?channel=feishu&target=oc_xxx
Content-Type: application/json
Query 参数
channel:feishu或telegram,大小写不敏感;不接受larktarget: 接收目标 ID
接口只接受 Grafana 13 统一告警 Webhook。每个 firing 告警实例必须提供完整的 summary annotation,
缺失时接口返回错误,不从标签或查询值推断消息内容。description annotation 可用于补充规则说明。
同一通知组中已恢复的告警项不会出现在当前异常列表中。
统一告警可以通过 notificationSortKey 和 notificationSortOrder annotations 对当前异常列表排序,
notificationSortOrder 支持 asc 和 desc。数值排序需要忽略正负号时,可以设置
notificationSortAbsolute=true。未设置排序字段时保持 Grafana Webhook 的原始顺序。
Payload 示例
{
"receiver": "Feishu - 监控 - 程序",
"status": "firing",
"commonLabels": {
"alertname": "CPU 使用率过高"
},
"commonAnnotations": {
"notificationType": "alert",
"notificationSortOrder": "desc"
},
"alerts": [
{
"status": "firing",
"labels": {
"alertname": "CPU 使用率过高",
"instance": "server-01"
},
"annotations": {
"summary": "实例: server-01, CPU 使用率: 95.5%",
"notificationSortKey": "95.5"
},
"values": {
"A": 95.5
}
}
]
}GET /api/chats?channel=feishu
| 变量 | 说明 | 默认值 |
|---|---|---|
| APP_SERVER_HOST | 服务监听地址 | 0.0.0.0 |
| APP_SERVER_PORT | 服务监听端口 | 8000 |
| APP_SERVER_BASE_URL | 服务基础 URL | http://localhost:8000/ |
| APP_FEISHU_ID | 飞书应用 App ID | - |
| APP_FEISHU_SECRET | 飞书应用 App Secret | - |
| APP_TELEGRAM_BOT_TOKEN | Telegram Bot Token | - |
| APP_LOG_LEVEL | 日志级别:debug/info/warn/error | info |
| QUEUE_RATE_LIMIT | 发送速率限制 (个/秒) | 1.0 |
| QUEUE_MAX_ATTEMPTS | 单条消息最多发送次数(包含首次发送) | 3 |
| QUEUE_RETRY_DELAY | 重试基础延迟(指数退避) | 1s |
| QUEUE_BUFFER_SIZE | 每个目标的队列缓冲大小 | 1000 |
| QUEUE_IDLE_TIMEOUT | 队列空闲多久后自动释放 | 5m |
为了保护下游服务(飞书、Telegram)不被请求淹没并避免触发其频率限制,本服务内置了针对 每个目标(Channel + Target) 的独立限频器。
- 限频策略:每个
channel + target组合拥有独立的发送队列和限频器。- 默认限频速率为 1条/秒(可通过
QUEUE_RATE_LIMIT配置)。 - 例如:同时向飞书群 A 和群 B 发送消息,它们互不影响,各自都能达到 1条/秒的速率。但如果短时间内向群 A 发送大量消息,这些消息会排队并按 1条/秒的速度依次发出。
- 默认限频速率为 1条/秒(可通过
- 自动重试:如果发送失败(例如网络波动或 API 临时错误),系统会自动重试。
- 默认最多发送 3 次,即首次发送失败后最多重试 2 次(
QUEUE_MAX_ATTEMPTS)。 - 采用指数退避策略,默认第 1 次重试延迟 1s,第 2 次重试延迟 2s(
QUEUE_RETRY_DELAY配置基础延迟)。 - 达到最大发送次数后仍失败的任务将被丢弃,并记录错误日志。
- 默认最多发送 3 次,即首次发送失败后最多重试 2 次(
请确保你的飞书自建应用已开通以下权限,并发布了版本:
- im:message:send_as_bot (以应用身份发送消息):这是发送消息的基础权限。
- im:chat:list (获取群组列表):如果你使用了
/api/chats接口来列出群组,则需要此权限。
你可以将 Bot 添加到群组,然后通过访问 https://api.telegram.org/bot<YourBOTToken>/getUpdates 查看更新,在 JSON 响应中找到 chat.id 字段(通常以 -100 开头)。或者使用第三方工具/Bot(如 @get_id_bot)来获取。