首页 > 其他分享 >通过go自定义alertmanager 发送通知的webhook

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

时间:2024-08-07 15:23:17浏览次数:16  
标签:alertmanager http string err webhook json data 自定义

本文主要是大体介绍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的代码

  1. 创建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

相关文章

  • 笔记:从Aurora 8b/10b 到Aurora 64b/66b (三):自定义PHY层收发
    相较于8/10来说没那么复杂,需要考虑的情况只有八种;但是gearbox的控制需要额外的心思:每三十二周期所有操作都需要停止;这一点在收发都需要注意;RX:核心思想是利用header做检测,将夹杂在数据流中的控制包滤除掉;modulegt_phy_rx(inputwirei_rx_clk......
  • golang sliver二次开发自定义命令(格式乱后面再调)
    准备工作sliver客户端和服务端之间命令的通信采用的grpc,服务端和和植入程序通信使用的protobuf,所以在开发之前需要了解grpc和protobuf,相关文档:https://jergoo.gitbooks.io/go-grpc-practice-guide/content/chapter2/hello-grpc.htmlhttps://jergoo.gitbooks.io/go-grpc-pra......
  • Cython将Numpy数组转为自定义结构体
    技术背景前面我们写过几篇关于Cython的文章,例如Cython计算谐振势、Cython与C语言的结合、Cython调用CUDAKernel函数。Cython有着非常Pythonic的编程范式,又具备着接近于C语言的性能,因此在很多对于性能有要求的Python软件中都会使用到Cython的性能优化。Cython的基本工作流程是,先......
  • 从多个方面了解工作流自定义表单的优势
    进入流程化办公新时代,需要借助低代码技术平台、工作流自定义表单的诸多优势特点,打破信息孤岛,做好各部门之间的沟通协调工作,实现高效率发展。很多大中型企业都想了解工作流自定义表单究竟有什么样的优势和特点,现在,我们通过分析它的优势和特点,来进一步深入了解工作流自定义表单吧。......
  • 数据同步的艺术:在SQL Server中打造自定义同步引擎
    数据同步的艺术:在SQLServer中打造自定义同步引擎在企业级应用中,数据同步是确保数据一致性的关键技术。SQLServer提供了多种数据同步机制,包括事务复制、合并复制和数据仓库等。然而,在特定场景下,我们可能需要实现更灵活的自定义数据同步机制。本文将深入探讨如何在SQLServ......
  • 帝国CMS自定义页面动态设置
    帝国CMS提供灵活的自定义页面功能,允许用户创建和管理动态内容页面。以下步骤介绍如何设置帝国CMS自定义页面动态:1.创建自定义页面在帝国CMS管理后台,导航到"栏目">>"自定义页面">>"添加自定义页面"。输入页面标题和页面内容,然后单击"提交"保存页面。2.定义字段转到"栏目">>"......
  • 记一次 Android 自定义相机拍照奔溃bug事件
    最近在开发一个美颜的相机功能,需要自定义抓取相机回调的数,生成照片并保存到相册,需要自定义保存照片。相机开始使用时没有任何问题,测试拍照几次后突然奔溃,跟踪代码日志发现是图片保存失败,同样的代码,同样的逻辑,正常使用很多次以后才奔溃报错,根据日志找到报错的位置,ContentValue......
  • 织梦dedecms调用文章列表时候判断文章自定义属性
    有时候我们需要通过判断文章的属性来给相应的属性以相应的样式,例如为推荐的文章添加推荐的标志等等。例如以下代码就可以判断出文章是否是推荐和图片这两个属性,并作不同的样式输出:[field:arrayrunphp=&#39;yes&#39;]if(@me[&#39;flag&#39;]==&#39;c,p&#39;)@me=&#39;<em>......
  • wordpress教程栏目给大家介绍自定义wordpress文件上传路径的方法
    自WordPress3.5版本开始,隐藏了后台媒体设置页面的“默认上传路径和文件的完整URL地址”选项,可以通过下面的代码将该选项调出来。将下面的代码添加到当前主题functions.php文件中,就可以调出该选项:if(get_option(&#39;upload_path&#39;)==&#39;wp-content/uploads&#39;||get_op......
  • 在 jupyter Notebook 中导入自定义模块的问题
    假设我们有一个如下的文件结构,#注意:不是实际的目录结构,而是类似的root../tests../src../__init__.pyutils../__init__.pydata.pypipeline.pysqlal../__init__.pysql_alchm.pytest.pyprocess.ipynb......