前言

  • 功能:作为 alertmanager 的 webhook receiver,提取需要的数据转发到钉钉群机器人的webhook
  • web框架:gin
  • alertmanager版本:0.24
  • 系统版本:ubuntu 20.04
  • 功能比较简单,所以就随便写了,全部属于main

原始json数据示例

{
"receiver": "web\\.hook",
"status": "firing",
"alerts": [{
"status": "firing",
"labels": {
"alertname": "node",
"instance": "192.168.0.10",
"job": "rh7",
"severity": "critical"
},
"annotations": {
"description": "rh7 192.168.0.10 节点断联已超过1分钟!",
"summary": "192.168.0.10 down "
},
"startsAt": "2022-04-28T08:44:23.05Z",
"endsAt": "0001-01-01T00:00:00Z",
"generatorURL": "http://localhost.localdomain:19090/graph?g0.expr=up+%3D%3D+0\u0026g0.tab=1",
"fingerprint": "726681bf4674e8a5"
}],
"groupLabels": {
"alertname": "node"
},
"commonLabels": {
"alertname": "node",
"instance": "192.168.0.10",
"job": "rh7",
"severity": "critical"
},
"commonAnnotations": {
"description": "rh7 192.168.0.10 节点断联已超过1分钟!",
"summary": "192.168.0.10 down "
},
"externalURL": "http://192.168.0.10:19092",
"version": "4",
"groupKey": "{}:{alertname=\"node\"}",
"truncatedAlerts": 0
}

示例代码

  • model.go(定义结构体)
package main

// 定义接收JSON数据的结构体
type ReqAlert struct {
Status string `json:"status"`
StartsAt string `json:"startsAt"`
EndsAt string `json:"endsAt"`
GeneratorURL string `json:"generatorURL"`
Fingerprint string `json:"fingerprint"`
Labels ReqAlertLabel `json:"labels"`
Annotations ReqAlertAnnotations `json:"annotations"`
} type ReqGroupLabels struct {
Alertname string `json:"alertname"`
} type ReqCommonLabels struct {
Alertname string `json:"alertname"`
Instance string `json:"instance"`
Job string `json:"job"`
Severity string `json:"severity"`
} type ReqCommonAnnotations struct {
Description string `json:"description"`
Summary string `json:"summary"`
} type ReqAlertLabel struct {
Alertname string `json:"alertname"`
Instance string `json:"instance"`
Job string `json:"job"`
Severity string `json:"severity"`
} type ReqAlertAnnotations struct {
Description string `json:"description"`
Summary string `json:"summary"`
} type RequestBody struct {
// alertmanager传来的请求体
Receiver string `json:"receiver"`
Status string `json:"status"`
ExternalURL string `json:"externalURL"`
Version string `json:"version"`
GroupKey string `json:"groupkey"`
TruncatedAlerts float64 `json:"truncatedAlerts"`
Alert []ReqAlert `json:"alerts"`
GroupLabels ReqGroupLabels `json:"groupLabels"`
CommonLabels ReqCommonLabels `json:"commonLabels"`
CommonAnnotations ReqCommonAnnotations `json:"commonAnnotations"`
}
  • dingmsg.go(对接钉钉webhook,注意替换webhook的url)
package main

import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"strings"
) type Md struct {
Title string `json:"title"`
Text string `json:"text"`
} type Ding struct {
Msgtype string `json:"msgtype"`
Markdown Md `json:"markdown"`
} func DingMarshal(text string) string {
// struct序列化为json
var myjson Ding = Ding{
Msgtype: "markdown",
Markdown: Md{
Title: "锄田测试钉钉机器人",
Text: text,
},
}
va, err := json.Marshal(myjson)
if err != nil {
panic(err)
}
return string(va)
} func PostUrl(jsondata string) {
// 发起post请求
// 替换钉钉群机器人的webhook
url := "https://oapi.dingtalk.com/robot/send?access_token=123456"
var jsonstr = []byte(jsondata)
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonstr))
if err != nil {
log.Fatal(err)
} req.Header.Set("Content-Type", "application/json;charset=utf-8")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Printf("钉钉webhook响应: %v\n", string(body))
} func SpliceString(status, description, summary string) string {
// 拼接字符串
var rst strings.Builder
rst.WriteString("# 锄田测试钉钉机器人 \n\n")
rst.WriteString("- status: " + status + " \n\n")
rst.WriteString("- description: " + description + " \n\n")
rst.WriteString("- summary: " + summary + " \n\n")
return rst.String()
}
  • main.go
package main

import (
"context"
"errors"
"fmt"
"io"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time" "github.com/gin-gonic/gin"
) func ParseJson(c *gin.Context) {
// 解析AlertManager 传递的 json 数据
var json RequestBody
// 将数据解析到结构体中
if err := c.ShouldBindJSON(&json); err != nil {
// 返回错误信息
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
} // 遍历json中alerts数据
for k, v := range json.Alert {
fmt.Printf("k: %d, status: %s, description: %s, summary: %s \n", k, v.Status, v.Annotations.Description, v.Annotations.Summary)
text := SpliceString(v.Status, v.Annotations.Description, v.Annotations.Summary)
va := DingMarshal(text)
PostUrl(va)
} // 返回给客户端的消息
c.JSON(http.StatusOK, gin.H{
"msg": "success",
})
} func main() {
// 设置gin运行模式,可选:DebugMode、ReleaseMode、TestMode
gin.SetMode(gin.ReleaseMode) // 关闭控制台日志颜色
gin.DisableConsoleColor() // 记录到文件
f, _ := os.OpenFile("gin.log", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
gin.DefaultWriter = io.MultiWriter(f) r := gin.Default()
// 只接受来自127.0.0.1的请求
r.SetTrustedProxies([]string{"127.0.0.1"}) v1 := r.Group("/v1")
{
v1.POST("/alert", ParseJson)
} // 设置程序优雅退出
srv := &http.Server{
Addr: "127.0.0.1:19100",
Handler: r,
} go func() {
if err := srv.ListenAndServe(); err != nil && errors.Is(err, http.ErrServerClosed) {
log.Printf("listen: %s\n", err)
}
}() quit := make(chan os.Signal)
signal.Notify(quit, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
<-quit
log.Println("Shutting down server...")
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel() if err := srv.Shutdown(ctx); err != nil {
log.Fatal("Server forced to shutdown:", err)
} log.Println("Server exiting")
}

使用示例

  1. 导入依赖
go mod tidy
  1. 编译
go build -o goalert.bin ./main.go ./model.go ./dingmsg.go
  1. 运行
./goalert.bin
  1. 测试。使用python + requests 测试。python代码如下
import requests

# 注意json字符串的代码转为utf-8,否则会报Unicode的错误
# 使用json原字符串,而不是字典
json_firing = r"""
{"receiver":"web\\.hook","status":"firing","alerts":[{"status":"firing","labels":{"alertname":"node","instance":"192.168.0.10","job":"rh7","severity":"critical"},"annotations":{"description":"rh7 192.168.0.10 节点断联已超过1分钟!","summary":"192.168.0.10 down "},"startsAt":"2022-04-28T08:44:23.05Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://localhost.localdomain:19090/graph?g0.expr=up+%3D%3D+0\u0026g0.tab=1","fingerprint":"726681bf4674e8a5"}],"groupLabels":{"alertname":"node"},"commonLabels":{"alertname":"node","instance":"192.168.0.10","job":"rh7","severity":"critical"},"commonAnnotations":{"description":"rh7 192.168.0.10 节点断联已超过1分钟!","summary":"192.168.0.10 down "},"externalURL":"http://192.168.0.10:19092","version":"4","groupKey":"{}:{alertname=\"node\"}","truncatedAlerts":0}
""".encode("utf-8").decode("latin1") url = "http://127.0.0.1:19100/v1/alert" resp = requests.post(url=url, data = json_firing, headers={"Content-Type": "application/json"}) print(resp.text)
  1. alertmanager配置略过

补充

  • 钉钉可以通过面对面建群的方式建一个单人群,单人群也能添加机器人。
  • 如果不知道alertmanager发送的json数据是什么样,可以写个服务端,直接接收数据不解析,在控制台原样输出字符串。示例代码如下:
package main

import (
"fmt"
"io/ioutil"
"net/http"
) func f1(w http.ResponseWriter, r *http.Request) {
// 向客户端响应ok
defer fmt.Fprintf(w, "ok\n") // 获取客户端的请求方式
fmt.Println("method:", r.Method)
// 获取客户端请求的body
body, err := ioutil.ReadAll(r.Body)
if err != nil {
fmt.Printf("read body err, %v\n", err)
return
}
fmt.Println("json: ", string(body))
} func main() {
http.HandleFunc("/", f1)
http.ListenAndServe("127.0.0.1:8888", nil)
}

go接收alertmanager告警并发送钉钉的更多相关文章

  1. pinpoint实现告警推送至钉钉和微信群

    前言 在前面的文章中,我们学习了如何通过java实现将消息发送到钉钉.和将消息发送到微信群聊. 基于上述基础,我们今天来接入pinpoint的告警,发送到钉钉群. 实操前准备 开始之前,推荐阅读一下, ...

  2. 使用 Prometheus Alertmanager 模块发送 Doris 异常信息至钉钉报警群

    基础环境 1.Prometheus 版本:2.22.2 下载地址: https://github.com/prometheus/prometheus/releases/download/v2.22.2 ...

  3. 一个人的安全部之ELK接收Paloalto日志并用钉钉告警

    起因 通报漏洞后,开发未能及时修复漏洞,导致被攻击,领导说我发现被攻击的时间晚了,由于一个人安全部精力有限未能及时看IPS告警,于是做了个钉钉告警. 本人环境介绍 ubuntu 14.04 pytho ...

  4. Docker+Prometheus+Alertmanager+Webhook钉钉告警

    Docker+Prometheus+Alertmanager+Webhook钉钉告警 1.环境部署 1.1 二进制部署 1.2 docker部署 1.2.1 webhook 1.2.2 alertma ...

  5. kube-promethues监控告警详解(邮件、钉钉、微信、自研平台)

    Alertmanager已经在前面Prometheus初体验(三)已经介绍过了.现在介绍一下在kube-promethues里面怎么修改alertmanager配置文件,以及怎么通过各种媒介发送信息. ...

  6. prometheus grafana graylog 钉钉告警 短信告警 电话告警系统 PrometheusAlert

    PrometheusAlert 简介 PrometheusAlert是开源的运维告警中心消息转发系统,支持主流的监控系统Prometheus,日志系统Graylog和数据可视化系统Grafana发出的 ...

  7. prometheus-alertmanager告警推送到钉钉

    1. Prometheus告警简介 告警能力在Prometheus的架构中被划分成两个独立的部分.如下所示,通过在Prometheus中定义AlertRule(告警规则),Prometheus会周期性 ...

  8. Istio on ACK集成生态(2): 扩展AlertManager集成钉钉助力可观测性监控能力

    阿里云容器服务Kubernetes(简称ACK)支持一键部署Istio,可以参考文档在ACK上部署使用Isito.Istio on ACK提供了丰富的监控能力,为网格中的服务收集遥测数据,其中Mixe ...

  9. 基础架构之日志管理平台及钉钉&邮件告警通知

    接上一篇,我们继续解释如何把ELK跟钉钉及发送邮件功能结合起来,让我们及时的了解重要日志并快速反馈. Sentinel 安装,项目介绍在https://github.com/sirensolution ...

  10. Zabbix通过与微信、钉钉整合实现实时告警

    abbix可以通过多种方式把告警信息发送到指定人,常用的有邮件,短信报警方式,但是越来越多的企业开始使用zabbix结合微信.钉钉作为主要的告警方式,这样可以及时有效的把告警信息推送到接收人,方便告警 ...

随机推荐

  1. git仓库过渡,同时向两个仓库推送代码

    公司部门被大佬收购,产品项目迁移新公司仓库,过渡期间产品上线流程继续使用原公司的,新公司部署新系统后通过域名重定向逐渐将用户引流到新系统上完成切换,最后关闭原公司系统及上线流程. 过渡期间新功能代码需 ...

  2. 2022-09-04:以下go语言代码输出什么?A:不能编译;B:45;C:45.2;D:45.0。 package main import ( “fmt“ ) func main() {

    2022-09-04:以下go语言代码输出什么?A:不能编译:B:45:C:45.2:D:45.0. package main import ( "fmt" ) func main ...

  3. 2021-03-25:如何把长url转换为短url?

    2021-03-25:如何把长url转换为短url? 福大大 答案2021-03-25: 1.长url和短url一一映射.想采用某种算法,把长url和短url做一一映射.后来发现,这种方法是行不通的. ...

  4. [AGC001E] BBQ Hard题解

    Problem [AGC001E] BBQ Hard 计算: \[\sum_{i=1}^{n}\sum_{j=i+1}^n\binom{a_i+b_i+a_j+b_j}{a_i+a_j} \] 其中\ ...

  5. 分库分表的 21 条法则,hold 住!

    大家好,我是小富- (一)好好的系统,为什么要分库分表? 本文是<分库分表ShardingSphere5.x原理与实战>系列的第二篇文章,距离上一篇文章已经过去好久了,惭愧惭愧- 还是不着 ...

  6. python爬虫防止IP被封的一些措施(转)

    python爬虫防止IP被封的一些措施(转) 在编写爬虫爬取数据的时候,因为很多网站都有反爬虫措施,所以很容易被封IP,就不能继续爬了.在爬取大数据量的数据时更是瑟瑟发抖,时刻担心着下一秒IP可能就被 ...

  7. c#优雅高效的读取字节数组——不安全代码(1)

    在开发上位机的经历中,会有很多需要和下位机交互通信的场景,大多数都会定义一个和硬件的通信协议,最终在上位机代码中的形式其实就是符合通信协议的字节数组. 目录 场景 如何解析字节数组到类或结构体中 建立 ...

  8. 系统MySQL服务无法启动报错1067的四种解决方法win7系统MySQL服务无法启动报错1067的四种解决方法

        有些win7系统用户在登陆mysql或者重装mysql时出现"无法启动MYSQL服务,错误1067",而且重启.修复注册表都没办法解决问题.那么遇到MySQL服务无法启动问 ...

  9. 为teamcity的代码语法检查工具pyflakes增加支持python2和python3

    TeamCity和pyflakes TeamCity是一款由JetBrains公司开发的持续集成和部署工具,它提供了丰富的功能来帮助团队协作进行软件开发.其中包括代码检查.自动化构建.测试运行.版本控 ...

  10. SignalR+Hangfire 实现后台任务队列和实时通讯

    SignalR+Hangfire 实现后台任务队列和实时通讯 1.简介: SignalR是一个.NET的开源框架,SignalR可使用Web Socket, Server Sent Events 和 ...