本文主要是大体介绍webhook的代码以及涉及到的服务部署,详细配置需要自己弄
Prometheus、alertmanager部署
先创建alertmanager、Prometheus的docker-compose yaml文件,下面只是把服务运行起来,具体功能需要自己配置,如果有就跳过
version: '3'
services:
prometheus:
image: prom/prometheus
ports:
- '9090:9090'
volumes:
- prometheus_data:/etc/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--web.enable-lifecycle'
restart: always
grafana:
image: grafana/grafana
ports:
- '3000:3000'
depends_on:
- prometheus
restart: always
alertmanager:
image: prom/alertmanager
ports:
- '9093:9093'
volumes:
- alertmanager_data:/etc/alertmanager
command:
- '--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
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,下面代码可以输出,配置好alertmanager的webhook和告警规则,接收post请求
package main
import (
"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的代码
- 创建main.go文件,代码如下:
package main
import (
"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 AlertNotification
if 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,配置一条告警,查看是否能发到飞书,其他平台也类似
标签:alertmanager,http,string,err,webhook,json,data,自定义 From: https://blog.csdn.net/nange_nice/article/details/140977347