通过go自定义alertmanager 发送通知的webhook

ops/2024/10/20 4:06:14/

本文主要是大体介绍webhook的代码以及涉及到的服务部署,详细配置需要自己弄

alertmanager_1">Prometheus、alertmanager部署

先创建alertmanager、Prometheus的docker-compose yaml文件,下面只是把服务运行起来,具体功能需要自己配置,如果有就跳过

version: '3'
services:prometheus:image: prom/prometheusports:- '9090:9090'volumes:- prometheus_data:/etc/prometheuscommand:- '--config.file=/etc/prometheus/prometheus.yml'- '--web.enable-lifecycle'restart: alwaysgrafana:image: grafana/grafanaports:- '3000:3000'depends_on:- prometheusrestart: alwaysalertmanager:image: prom/alertmanagerports:- '9093:9093'volumes:- alertmanager_data:/etc/alertmanagercommand:- '--config.file=/etc/alertmanager/alertmanager.yml'restart: always
volumes:prometheus_data: {}alertmanager_data: {}

docker-compose up -d运行起来,如果镜像拉不下,根据下面配置镜像加速

cat /etc/docker/daemon.json 
{"registry-mirrors":["https://docker.anyhub.us.kg","https://dockerhub.icu","https://docker.awsl9527.cn"
]}
sudo systemctl daemon-reload
sudo systemctl restart docker

alertmanagerbody_52">alertmanager请求body

{"receiver": "web\\.hook","status": "firing","alerts": [{"status": "firing","labels": {"alertname": "process_cpu_seconds_total","app": "myrules","instance": "localhost:9090","job": "prometheus","severity": "info","type": "constom"},"annotations": {"description": "description info","summary": "High request latency"},"startsAt": "2024-08-05T09:50:13.828Z","endsAt": "0001-01-01T00:00:00Z","generatorURL": "http://b985ae1139a4:9090/graph?g0.expr=process_cpu_seconds_total%7Binstance%3D%22localhost%3A9090%22%2Cjob%3D%22prometheus%22%7D+%3C+3\u0026g0.tab=1","fingerprint": "73caa1e73b23db5a"}],"groupLabels": {"alertname": "process_cpu_seconds_total"},"commonLabels": {"alertname": "process_cpu_seconds_total","app": "myrules","instance": "localhost:9090","job": "prometheus","severity": "info","type": "constom"},"commonAnnotations": {"description": "description info","summary": "High request latency"},"externalURL": "http://c487130b876e:9093","version": "4","groupKey": "{}:{alertname=\"process_cpu_seconds_total\"}","truncatedAlerts": 0
}

如果想看请求的body,下面代码可以输出,配置好alertmanagerwebhook和告警规则,接收post请求

package mainimport ("fmt""io""log""net/http"
)func main() {http.HandleFunc("/alert", handleData)log.Println("Listening on :8086...")err := http.ListenAndServe(":8086", nil)if err != nil {log.Fatal("ListenAndServe: ", err)}
}func handleData(w http.ResponseWriter, r *http.Request) {if r.Method != http.MethodPost {http.Error(w, "Only POST method is allowed", http.StatusMethodNotAllowed)return}// 读取请求体body, err := io.ReadAll(r.Body)if err != nil {http.Error(w, "Failed to read request body", http.StatusInternalServerError)return}// 打印请求体中的原始JSON数据fmt.Printf("Received JSON data: %s\n", body)// 返回成功响应w.WriteHeader(http.StatusOK)w.Write([]byte("Data received"))

webhook_141">涉及到webhook的代码

  1. 创建main.go文件,代码如下:
package mainimport ("bytes""encoding/json""fmt""io""log""net/http""github.com/gin-gonic/gin"
)// 根据body定义存储alertmanager的 json 结构体
type Alert struct {Status     string            `json:"status"`Labels     map[string]string `json:"labels"`Annotations map[string]string `json:"annotations"`StartsAt   string            `json:"startsAt"`EndsAt     string            `json:"endsAt"`GeneratorURL string           `json:"generatorURL"`Fingerprint string            `json:"fingerprint"`
}type AlertNotification 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"`GroupKey    string          `json:"groupKey"`TruncatedAlerts int           `json:"truncatedAlerts"`
}
// Message 结构体用于构建消息的内容
type Message struct {MsgType string      `json:"msg_type"`Content interface{} `json:"content"`
}
// TextContent 结构体用于构建文本消息的内容
type TextContent struct {Text string `json:"text"`
}var feishuhook string = "https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxx"func handleData(c *gin.Context) {var data AlertNotificationif err := c.ShouldBindJSON(&data); err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})return}// 打印请求体中的原始JSON数据fmt.Println("Received JSON data: ", data)if data.Status == "firing" {err := SendMessage(feishuhook, data.GroupLabels["alertname"] + "有故障")if err != nil {fmt.Println(err)}}else {err := SendMessage(feishuhook, data.GroupLabels["alertname"] + "已恢复")if err != nil {fmt.Println(err)}}// 返回成功响应c.JSON(http.StatusOK, gin.H{"msg": "msg sent successfully",})
}func SendMessage(webhookURL string, text string) error {// 创建消息内容textContent := TextContent{Text: text}message := Message{MsgType: "text",Content: textContent,}// 将消息转换为JSON格式jsonMessage, err := json.Marshal(message)if err != nil {return fmt.Errorf("error marshaling message to JSON: %w", err)}// 发送HTTP POST请求resp, err := http.Post(webhookURL, "application/json", bytes.NewBuffer(jsonMessage))if err != nil {return fmt.Errorf("error sending HTTP POST request: %w", err)}defer resp.Body.Close()// 检查响应状态码body, _ := io.ReadAll(resp.Body)if resp.StatusCode != http.StatusOK {return fmt.Errorf("unexpected HTTP status code: %d, response body: %s", resp.StatusCode, body)}return nil
}func main() {// 设置为release模式gin.SetMode(gin.ReleaseMode)r := gin.Default()r.POST("/alert", handleData)log.Println("Listening on :8080...")r.Run(":8080")
}

到目前为止就可以了,运行go run main.go,配置一条告警,查看是否能发到飞书,其他平台也类似


http://www.ppmy.cn/ops/91606.html

相关文章

CSP-J 复赛 模拟题6

1.大小写字母互换: 题目描述 由输入给定一个字符串,你的任务是将原字符串中的大写字母转换成其对应的小写字母,还要将原字符串中的小写字母转换成对应的大写字母,其余字符不变。 输出转换之后得到的新字符串。 输入格式 一行…

Mysql聚簇索引与非聚簇索引B+树实现区别详解

聚簇索引 特点: 索引和数据保存在同一个B树中,每一页 也就是每一个节点是按照主键的大小顺序排成一个单项链表,B树的每一层的页与页之间也是根据主键大小顺序排成一个双向链表,非叶子节点存储的是记录的主键指向的页号&#xff…

大整数求余c++

#include<bits/stdc.h> using namespace std; int main(){string a;long long b;cin>>a>>b;int la.size();long long t0;for(int i0;i<l;i){tt*10(a[i]-0);tt%b;}cout<<t;return 0; } 这段代码a可以输入比long long的最大值&#xff08;9223372036…

Android NDK/JNI面试题大全及参考答案(3万字长文)

目录 什么是NDK?它主要用来做什么? 为什么在Android开发中使用NDK? 描述一下NDK和JDK之间的关系 举出一些使用NDK开发的应用场景 什么是JNI?它如何与NDK配合使用? 如何安装和配置Android NDK? 在Android Studio中如何配置NDK路径? 描述一下NDK工具链中的主要工具…

Redis 7.x 系列【37】旁路缓存模式

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 本系列Redis 版本 7.2.5 源码地址&#xff1a;https://gitee.com/pearl-organization/study-redis-demo 文章目录 1. 缓存1.1 数据库缓存1.2 数据一致性 2. 旁路缓存模式2.1 工作原理2.2 四种更新策略2…

mysql 字符串转数组

在 MySQL 中&#xff0c;可以使用内置的字符串函数 SUBSTRING_INDEX() 和 REPLACE() 来实现将字符串转换为数组。 首先&#xff0c;使用 REPLACE() 函数将字符串中的分隔符替换为空格&#xff0c;然后使用 SUBSTRING_INDEX() 函数将字符串按空格分割成多个子字符串。最后&…

【ARM】v8架构programmer guide(3)_ARMv8的寄存器

目录 4.ARMv8 registers 4.1 AArch64 特殊寄存器 4.1.1 Zero register 4.1.2 Stack pointer &#xff08;SP) 4.1.3 Program Counter &#xff08;PC) 4.1.4 Exception Link Register(ELR) 4.1.5 Saved Process Status Register &#xff08;SPSR&#xff09; 4.2 Proc…

springboot给类进行赋初值的四种方式

目录 1. 使用Value和ConfigurationProperties2. 使用PropertySource创建Person.java写一个测试类 3. 使用ImportResourceStudent类创建beans.xml在主类中引入测试 其他心得 1. 使用Value和ConfigurationProperties 这里不加赘述了&#xff0c;前面我也发过&#xff0c;这里就放…