使用企业微信的消息推送来发送告警

news/2026/1/17 15:49:50/文章来源:https://www.cnblogs.com/daveyhe/p/19496341

使用企业微信的消息推送来发送告警

实现 Prometheus 的 Alertmanager 与企业微信集成,让 Prometheus 触发的告警能够自动推送到企业微信的群聊/机器人中。

先创建企业微信机器人,复制机器人的 Webhook URL(格式类似:https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxx-xxxx-xxxxx-xxxx-xxxx),把机器人拉入群聊。

假设企业微信的消息推送 webhook 是 https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxx-xxxx-xxxxx-xxxx-xxxx,对该地址发起 HTTP POST 请求,即可实现给该群组发送消息:

curl 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxx-xxxx-xxxxx-xxxx-xxxx' \-H 'Content-Type: application/json' \-d '{"msgtype": "text","text": {"content": "hello world"}}'
  • msgtype:必须字段,中转端点必须生成该字段以适配,否则无法推送,常用的两种类型:
    • text:文本类型。
      {"msgtype": "text","text": {"content": "广州今日天气:29度,大部分多云,降雨概率:60%","mentioned_list":["wangqing","@all"],"mentioned_mobile_list":["13800001111","@all"]}
      }
      
    • markdown:markdown 类型。
      {"msgtype": "markdown","markdown": {"content": "实时新增用户反馈<font color=\"warning\">132例</font>,请相关同事注意。\n>类型:<font color=\"comment\">用户反馈</font>\n>普通用户反馈:<font color=\"comment\">117例</font>\n>VIP用户反馈:<font color=\"comment\">15例</font>"}
      }
      

先手动测试 markdown 类型的消息,看企业微信是否能正常收到消息:

curl 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxx-xxxx-xxxx' \-H 'Content-Type: application/json' \-d '{"msgtype": "markdown","markdown": {"content": "### 测试告警\n> 这是一条测试消息"}}'

为什么要用 webhook 中转?目的是让 Alertmanager 模板渲染后的结果严格匹配企业微信机器人要求的消息结构,要确保:

  • 企业微信机器人只接收特定格式的 JSON 数据,上面的 markdown 类型是告警场景最常用的(支持排版、高亮),渲染后的 JSON 格式要符合企业微信的规范。
  • content 字段要符合企业微信 markdown 的语法,要处理好一些特殊字符。

Alertmanager 以 JSON 格式向配置的 webhook 端点发送 HTTP POST 请求,固定格式:

{"version": "4","groupKey": <string>,              // key identifying the group of alerts (e.g. to deduplicate)"truncatedAlerts": <int>,          // how many alerts have been truncated due to "max_alerts""status": "<resolved|firing>","receiver": <string>,"groupLabels": <object>,"commonLabels": <object>,"commonAnnotations": <object>,"externalURL": <string>,           // backlink to the Alertmanager."alerts": [{"status": "<resolved|firing>","labels": <object>,"annotations": <object>,"startsAt": "<rfc3339>","endsAt": "<rfc3339>","generatorURL": <string>,      // identifies the entity that caused the alert"fingerprint": <string>        // fingerprint to identify the alert},...]
}

流程:

Alertmanager(固定的原始 JSON 格式) -> 中转端点(打包成企业微信机器人要求的格式) -> 企业微信机器人

下面用 golang 来实现这个中转端,也可以用其它语言实现比如 python。

alertmanager.yml 中配置:

...
# 模板文件
templates:- '/etc/alertmanager/templates/*.tmpl'# 接收器:定义告警的通知方式(邮件、WebHook 等)
receivers:...# 企业微信接收器(通过 WebHook)- name: 'wechat'webhook_configs:# golang 中转端- url: 'http://10.0.0.12:5000/wechat'send_resolved: true  # 告警恢复时也发送通知timeout: 15s

golang-wechat/main.go

package mainimport ("bytes""encoding/json""fmt""log""net/http""os""text/template""time"
)// Alertmanager 原始告警数据结构(与模板变量对应)
type AlertmanagerData struct {Receiver          string            `json:"receiver"`Status            string            `json:"status"`Alerts            []Alert           `json:"alerts"`GroupLabels       map[string]string `json:"groupLabels"`CommonLabels      map[string]string `json:"commonLabels"`CommonAnnotations map[string]string `json:"commonAnnotations"`ExternalURL       string            `json:"externalURL"`Version           string            `json:"version"`
}type Alert struct {Status      string            `json:"status"`Labels      map[string]string `json:"labels"`Annotations map[string]string `json:"annotations"`StartsAt    time.Time         `json:"startsAt"`EndsAt      time.Time         `json:"endsAt"`Fingerprint string            `json:"fingerprint"`
}// 企业微信消息结构(模板渲染结果需符合此格式)
type WechatMessage struct {MsgType  string `json:"msgtype"`Markdown struct {Content string `json:"content"`} `json:"markdown"`
}var (wechatWebhook stringtpl           *template.Template // 全局模板对象
)func main() {// 从环境变量获取配置wechatWebhook = os.Getenv("WECHAT_WEBHOOK_URL")port := os.Getenv("PORT")tplPath := os.Getenv("TEMPLATE_PATH") // 模板文件路径if port == "" {port = "5000" // 默认端口}if wechatWebhook == "" {log.Fatal("请设置环境变量 WECHAT_WEBHOOK_URL")}if tplPath == "" {tplPath = "/app/templates/wechat.tmpl" // 默认模板路径}// 加载并解析模板文件(只渲染 content 内容,不含 JSON 结构)var err errortpl, err = template.ParseFiles(tplPath)if err != nil {log.Fatalf("加载模板失败: %v", err)}log.Printf("成功加载模板,名称: %s,路径: %s", tpl.Name(), tplPath)// 注册 HTTP 路由http.HandleFunc("/wechat", forwardHandler)http.HandleFunc("/health", healthHandler)// 启动服务log.Printf("服务启动,监听端口: %s", port)log.Fatal(http.ListenAndServe(":"+port, nil))
}// 转发处理函数
func forwardHandler(w http.ResponseWriter, r *http.Request) {// 解析 Alertmanager 原始数据var alertData AlertmanagerDataif err := json.NewDecoder(r.Body).Decode(&alertData); err != nil {http.Error(w, "解析请求失败: "+err.Error(), http.StatusBadRequest)log.Printf("解析错误: %v", err)return}log.Printf("收到告警数据: %+v", alertData)// 用模板渲染 markdown.content 的文本内容(不含 JSON 结构)var contentBuf bytes.Buffer// 带有命名模板({{ define "wechat.message" }})的模板文件 使用 ExecuteTemplate 而不是 Executeif err := tpl.ExecuteTemplate(&contentBuf, "wechat.message", alertData); err != nil {http.Error(w, "模板渲染失败: "+err.Error(), http.StatusInternalServerError)log.Printf("模板渲染错误: %v", err)return}rawContent := contentBuf.String()log.Printf("渲染后的 content 原始内容: %s", rawContent)escapedContent := rawContent// 构造企业微信消息结构体var wechatMsg WechatMessagewechatMsg.MsgType = "markdown"wechatMsg.Markdown.Content = escapedContent// 序列化结构体为 JSON(自动处理所有特殊字符转义)jsonData, err := json.Marshal(wechatMsg)if err != nil {http.Error(w, "JSON 序列化失败: "+err.Error(), http.StatusInternalServerError)log.Printf("JSON 序列化错误: %v", err)return}log.Printf("最终发送的 JSON: %s", jsonData)// 转发到企业微信resp, err := http.Post(wechatWebhook, "application/json", bytes.NewBuffer(jsonData))if err != nil {http.Error(w, "转发失败: "+err.Error(), http.StatusInternalServerError)log.Printf("转发错误: %v", err)return}defer resp.Body.Close()if resp.StatusCode != http.StatusOK {http.Error(w, fmt.Sprintf("企业微信接口错误,状态码: %d", resp.StatusCode), http.StatusInternalServerError)log.Printf("企业微信接口错误,状态码: %d", resp.StatusCode)return}// 返回成功响应w.WriteHeader(http.StatusOK)w.Write([]byte(`{"status": "success"}`))
}// 健康检查
func healthHandler(w http.ResponseWriter, r *http.Request) {w.WriteHeader(http.StatusOK)w.Write([]byte(`{"status": "healthy"}`))
}

匹配上面 golang 中转程序的模板 templates/wechat.tmpl

{{ define "wechat.message" }}{{- range $index, $alert := .Alerts -}}
{{- if gt $index 0 }}
---
{{ end }}{{- if eq $alert.Status "firing" }}
### 🚨 监控报警(故障告警通知)
{{- else }}
### ✅ 监控报警(恢复通知)
{{- end }}
- **告警类型**: {{ if $alert.Labels.alertname }}{{ $alert.Labels.alertname }}{{ else }}未知告警{{ end }}
- **告警级别**: {{ if $alert.Labels.severity }}{{ $alert.Labels.severity }}{{ else }}未知级别{{ end }}
- **告警状态**: {{ $alert.Status }} {{ if eq $alert.Status "firing" }}故障{{ else }}恢复{{ end }}
- **故障主机**: {{ if $alert.Labels.instance }}{{ $alert.Labels.instance }}{{ else }}-{{ end }} {{ if $alert.Labels.device }}{{ $alert.Labels.device }}{{ else }}-{{ end }}
- **服务环境**: {{ if $alert.Labels.env }}{{ $alert.Labels.env }}{{ else }}未知环境{{ end }}
- **服务名称**: {{ if $alert.Labels.servicename }}{{ $alert.Labels.servicename }}{{ else }}未知服务{{ end }}
- **告警主题**: {{ if $alert.Annotations.summary }}{{ $alert.Annotations.summary }}{{ else }}无主题{{ end }}
- **告警详情**: {{ if $alert.Annotations.message }}{{ $alert.Annotations.message }}{{ end }}{{ if and $alert.Annotations.message $alert.Annotations.description }};{{ end }}{{ if $alert.Annotations.description }}{{ $alert.Annotations.description }}{{ else }}无详情{{ end }}
{{- if $alert.Annotations.value }}
- **触发阈值**: {{ $alert.Annotations.value }}
{{- end }}
- **故障时间**: {{ ($alert.StartsAt.Add 28800e9).Format "2006-01-02 15:04:05" }}
{{- if eq $alert.Status "resolved" }}
- **恢复时间**: {{ if not $alert.EndsAt.IsZero }}{{ ($alert.EndsAt.Add 28800e9).Format "2006-01-02 15:04:05" }}{{ else }}持续中{{ end }}
{{- end }}{{- end }}{{ end }}

我的 Alertmanager 是用 docker 容器的形式运行的,进入容器中手动触发告警:

# docker exec -it alertmanager sh
amtool alert add \--alertmanager.url=http://localhost:9093 \--annotation summary="测试告警" \--annotation description="通过 amtool 发送的测试" \alertname=TestAlert \severity=critical \instance=test-server# 生成测试数据(保存为 test_alert.json)
cat > test_alert.json << EOF
{"version": "4","status": "firing","alerts": [{"status": "firing","labels": {"alertname": "HostOutOfMemory","severity": "warning","instance": "ubuntu-test-10-0-0-12","hostname": "test-host","env": "prod","servicename": "node-exporter"},"annotations": {"summary": "内存不足告警","description": "内存使用率超过90%"},"startsAt": "2025-08-09T08:00:00Z"}]
}
EOF# 用 amtool 测试模板渲染
amtool template render \--template.glob=/etc/alertmanager/templates/wechat.tmpl \--template.data=test_alert.json \--template.text='{{ template "wechat.message" . }}'

golang 中转端也是用 docker 容器的形式运行的,一个简单的 golang-wechat/Dockerfile

FROM golang:1.23-alpine AS builderWORKDIR /appCOPY main.go .# 启用 CGO 禁用(静态编译,避免依赖系统库)
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o mywechat main.goFROM alpine:3.20
WORKDIR /app
COPY --from=builder /app/mywechat .EXPOSE 5000ENTRYPOINT ["./mywechat"]

构建、启动:

docker build -t mywechat:v1 .docker stop mywechat
docker rm mywechat
docker run -d \
-v /etc/localtime:/etc/localtime:ro \
--user 1026:1026 \
--name mywechat \
-p 5000:5000 \
-e WECHAT_WEBHOOK_URL="https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxx-xxxx-xxxxx-xxxx-xxxx" \
-v templates:/app/templates \
mywechat:v1

接下来就可以手动触发一些告警来验证告警规则的处理了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1173977.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

7 大质感之选!艺术涂料防水防霉抗污耐刮擦品牌,进口高端色彩表现力强 - 速递信息

在现代高品质家居设计中,墙面不仅需要展现艺术美学,更需要具备卓越的物理性能。真正的贵族生活选择,既要满足视觉上的高级感,又要经得起时间的考验,具备防水防霉、抗污耐刮擦等实用性能。来自西欧的进口高端艺术涂…

2026年玻璃膏霜瓶厂家权威推荐榜单:粉底液瓶子/眼霜瓶/250ml橄榄油瓶/车载香水瓶/玻璃浮雕烛台源头厂家精选 - 品牌推荐官

在玻璃制品行业,定制化需求正以年均12%的速度增长,徐州冠天玻璃制品有限公司凭借其全链条生产能力,成为行业关注的焦点。作为一家集玻璃瓶生产、设计、加工、销售及瓶盖配套生产于一体的多元化企业,该公司已形成覆…

【机器人编队】基于A_Satr算法多机器人分布式动态避障领袖跟随者(含EKF)附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。 &#x1f34e; 往期回顾关注个人主页&#xff1a;Matlab科研工作室 &#x1f447; 关注我领取海量matlab电子书和数学建模资料 &#…

2026年餐饮油烟净化系统设备厂家权威推荐榜单:商用厨房设备/节能厨具设备/厨房排烟/厨房工程/净平油烟净化一体机源头厂家精选 - 品牌推荐官

在餐饮行业快速发展的背景下,油烟净化设备已成为保障空气质量、符合环保规范的核心装备。据统计,2025年国内餐饮油烟净化市场规模已突破200亿元,年复合增长率达12%,其中油烟净化设备、屋顶油烟净化、油烟净化系统等…

全国上门收老酒 京城亚南专业鉴定不压价 茅台五粮液变现选对渠道很关键 - 品牌排行榜单

“喝不完的名酒放着可惜,想变现又怕被坑”,这是很多老酒藏家的共同困扰。随着老酒收藏市场持续升温,茅台、五粮液等高端老酒的变现需求日益增长,但市场上鱼龙混杂的回收渠道,让不少藏友踩了坑:有的机构先报高价吸…

导入自己的手机APP使用时长数据,统计各APP使用占比,输出需卸载的高频低价值APP。

完整输出一个可运行的 Python 项目示例&#xff0c;用于导入手机 APP 使用时长数据、统计各 APP 使用占比、输出需卸载的高频低价值 APP。1. 实际应用场景描述在智能手机普及的今天&#xff0c;许多人每天会在多个 APP 上花费大量时间&#xff0c;但往往并不清楚哪些 APP 真正带…

2026年洁净棚厂家推荐榜:深圳市泰洁尔净化科技有限公司,千级洁净棚/十万级洁净棚/不锈钢洁净棚/洁净工作棚/百级洁净棚/万级洁净棚/可移动洁净棚厂家精选 - 品牌推荐官

在半导体、生物医药、电子光学等高精度制造领域,洁净环境是保障产品质量的核心要素。据行业统计,洁净度每提升一个等级,产品良率可提高5%-15%,而洁净棚作为局部高洁净度环境的实现载体,其市场需求正以年均12%的速…

告别Notion焦虑!这款全平台开源加密笔记神器,让你的隐私真正“上锁”

告别Notion焦虑&#xff01;这款全平台开源加密笔记神器&#xff0c;让你的隐私真正“上锁”引言在数字笔记工具遍地开花的今天&#xff0c;我们记录的内容越来越多&#xff1a;工作资料、学习笔记、灵感草稿、甚至是个人日记。可越依赖这些工具&#xff0c;越容易产生一个共同…

新手站长别哭!三个月把网站流量干翻倍的老炮儿碎碎念

新手站长别哭&#xff01;三个月把网站流量干翻倍的老炮儿碎碎念 新手站长别哭&#xff01;三个月把网站流量干翻倍的老炮儿碎碎念咱先把丑话说前头&#xff1a;SEO 真不是玄学&#xff0c;但比玄学还磨人关键词&#xff1a;别一上来就“口红口红口红”&#xff0c;先学会“装无…

【顶级SCI复现】虚拟电厂的多时间尺度调度:在考虑储能系统容量衰减的同时,整合发电与多用户负荷的灵活性研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

2026年优秀的T型精致钢,精致钢,精致钢龙骨厂家推荐及选择指南 - 品牌鉴赏师

引言在建筑与制造业蓬勃发展的2026年,精致钢作为一种关键材料,在高端制造与精品工程领域发挥着愈发重要的作用。为了给广大需求者提供真实、公正、客观的精致钢厂家推荐,我们依据相关权威数据和科学测评方法,精心打…

【顶级SCI复现】【日前调度和日内调度两个时间尺度】虚拟电厂多时间尺度调度优化研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

2026年1月徐州高端品质住宅市场深度分析盘点报告:锚定核心价值,甄选时代藏品 - 2026年企业推荐榜

引言:跨越周期的价值抉择 当前,徐州城市发展格局正经历深刻重塑,“东进南拓”与核心区焕新并举,推动高端住宅市场从单一的“地段论”向“综合价值论”演进。消费者,尤其是具备前瞻视野的城市菁英与实力家庭,其需…

如何使用Spring框架实现AOP?

一、先明确核心概念&#xff08;快速回顾&#xff09;在动手前&#xff0c;先理清 Spring AOP 的核心术语&#xff0c;避免后续代码理解混乱&#xff1a;切面&#xff08;Aspect&#xff09;&#xff1a;封装 “横切逻辑” 的类&#xff08;比如日志、权限校验、事务&#xff0…

济南的户外广告投放公司哪家便宜? - 工业品牌热点

2026年户外广告行业持续向场景化、数字化、整合化升级,广告主对户外广告的需求已从单一曝光转向降本增效、数据增值、资源整合的综合解决方案。无论是城市核心商圈的大屏投放、跨区域地铁公交的全域覆盖,还是高铁高速…

【顶级EI复现】基于断线解环思想的配电网辐射状拓扑约束建模方法(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

2026年评价高的胶粘剂,水性胶粘剂,注塑胶粘剂厂家选购参考指南 - 品牌鉴赏师

引言在 2026 年的工业制造与日常生活中,胶粘剂、水性胶粘剂以及注塑胶粘剂的应用愈发广泛,从厨具家电到汽车制造,从电子电气到建筑装饰,这些胶粘剂都发挥着至关重要的作用。然而,面对市场上众多的胶粘剂厂家,如何…

学霸同款8个AI论文写作软件,继续教育学生轻松搞定毕业论文!

学霸同款8个AI论文写作软件&#xff0c;继续教育学生轻松搞定毕业论文&#xff01; AI工具助力论文写作&#xff0c;轻松应对学术挑战 在当前的继续教育环境中&#xff0c;越来越多的学生面临着毕业论文的压力。无论是撰写初稿、修改内容&#xff0c;还是进行查重和降重&#x…

AI人工智能-强化学习-第十三周(小白)

一、强化学习(RL)和监督学习(SL)的核心区别 监督学习(比如分类, 回归):本质是“老师教学生”——给固定的“输入-输出答案”(比如图片->猫/狗标签、历史数据->股票价格),模型学“输入到答案的映射”,学会就只能做同类预测。 强化学习:是“学生自己摸爬滚打”…

【电压风险评估】基于720个样本与360个样本的Copula及蒙特卡罗推断结果比较研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…