golang实现钉钉机器人推送

效果展示

在这里插入图片描述

配置文件

{
    "dingding": {
        "token": "SECxxx",
        "webhook": "https://oapi.dingtalk.com/robot/send?access_token=xxx"
    },
    "alert": {
        "filter_type": "black",
        "white_list": [],
        "black_list": []
    }
}

markdown模板

#### <font color="black">{{.Src.AlertName}}</font>
>简介:<font color="black">{{.Src.RuleName}}</font><br>
>级别:<font color="{{.Color}}">{{.Src.Level}}</font><br>
>产品:<font color="black">{{.Src.Product}}</font><br>
>集群:<font color="black">{{.Src.Cluster}}</font><br>
>机器:<font color="black">{{.Src.Machine}}</font><br>
>时间:<font color="black">{{.Src.Time}}</font><br>
>详情:<font color="black">{{.Src.Detail}}</font><br>
>告警源:<font color="">{{.Src.Source}}</font><br>

代码

package service

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"text/template"
	"time"
	"zx_alert/config"
	"zx_alert/pkg/model"
	logg "zx_alert/utils/log"
)

const (
	tmpl = `#### <font color="black">{{.Src.AlertName}}</font>
>简介:<font color="black">{{.Src.RuleName}}</font><br>
>级别:<font color="{{.Color}}">{{.Src.Level}}</font><br>
>产品:<font color="black">{{.Src.Product}}</font><br>
>集群:<font color="black">{{.Src.Cluster}}</font><br>
>机器:<font color="black">{{.Src.Machine}}</font><br>
>时间:<font color="black">{{.Src.Time}}</font><br>
>详情:<font color="black">{{.Src.Detail}}</font><br>
>告警源:<font color="">{{.Src.Source}}</font><br>`
)

type DingDingPusher struct {
	Dest  string
	Src   AlertMsg
	Color string
}

type AlertMsg struct {
	RuleName  string
	AlertName string
	Level     string
	Product   string
	Cluster   string
	Machine   string
	Time      string
	Detail    string
	Source    string
}

func NewDingDingPusher(data model.AsoWebhookAlarm) *DingDingPusher {
	var (
		level   string
		cluster string
		product string
		machine string

		color string
	)
	switch data.EventLevel {
	case "FATAL":
		level = "P1"
		color = "red"
	case "SERIOUS":
		level = "P2"
		color = "orange"
	case "NORMAL":
		level = "P3"
		color = "yellow"
	case "NOTIFY":
		level = "P4"
		color = "greeen"
	}

	if data.Cluster == "" {
		cluster = "-"
	} else {
		cluster = data.Cluster
	}

	if data.Machine == "" {
		machine = "-"
	} else {
		machine = data.Machine
	}

	if data.Product == "" {
		product = "-"
	} else {
		product = data.Product
	}

	alertMsg := AlertMsg{
		RuleName:  data.RuleName,
		AlertName: data.AlertName,
		Level:     level,
		Product:   product,
		Cluster:   cluster,
		Machine:   machine,
		Time:      time.Unix(0, data.UpdateTime*int64(time.Millisecond)).Format("2006-01-02 15:04:05"),
		Detail:    data.Message,
		Source:    data.DataSource,
	}

	return &DingDingPusher{
		Src:   alertMsg,
		Dest:  "",
		Color: color,
	}
}

func (dp *DingDingPusher) RenderTemplate() error {
	t := template.Must(template.New("alert").Parse(tmpl))

	var buf bytes.Buffer
	if err := t.Execute(&buf, dp); err != nil {
		return fmt.Errorf("error executing template: %w", err)
	}

	dp.Dest = buf.String()

	// fmt.Printf("%s\n", dp.Dest)
	return nil
}

type DingTalkMessage struct {
	MsgType  string `json:"msgtype"`
	Markdown struct {
		Title string `json:"title"`
		Text  string `json:"text"`
	} `json:"markdown"`
}

type DingTalkText struct {
	Content string `json:"content"`
}

func (dp *DingDingPusher) Push() error {
	dingTalkMessage := DingTalkMessage{
		MsgType: "markdown",
		Markdown: struct {
			Title string `json:"title"`
			Text  string `json:"text"`
		}{
			Title: "Alert Notifications",
			Text:  dp.Dest,
		},
	}

	jsonMessage, err := json.Marshal(dingTalkMessage)
	if err != nil {
		return fmt.Errorf("failed to marshal message: %v", err)
	}

	timestamp := time.Now().UnixMilli() // 必须要用ms

	sign, err := dingdingSignature(timestamp, config.Conf.DingDingConfig.Token)
	if err != nil {
		return fmt.Errorf("failed to dingdingSignature: %v", err)
	}

	// url
	var urlBuilder strings.Builder
	urlBuilder.WriteString(config.Conf.DingDingConfig.Webhook)
	urlBuilder.WriteString("&")
	urlBuilder.WriteString("timestamp=")
	urlBuilder.WriteString(strconv.FormatInt(timestamp, 10))
	urlBuilder.WriteString("&")
	urlBuilder.WriteString("sign=")
	urlBuilder.WriteString(sign)

	// fmt.Println(urlBuilder.String())
	// os.Exit(0)
	req, err := http.NewRequest("POST", urlBuilder.String(), bytes.NewBuffer(jsonMessage))
	if err != nil {
		return fmt.Errorf("failed to create HTTP request: %v", err)
	}

	req.Header.Set("Content-Type", "application/json")

	// 发送请求
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return fmt.Errorf("failed to send request: %v", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("received non-200 response: %s", resp.Status)
	}

	msg := fmt.Sprintf("success! alert[%v]", dp.Src)
	logg.Logger.Info(msg)

	return nil
}

func dingdingSignature(ts int64, token string) (string, error) {
	stringToSign := fmt.Sprintf("%d\n%s", ts, token)

	h := hmac.New(sha256.New, []byte(token))
	h.Write([]byte(stringToSign))
	signData := h.Sum(nil)

	signature := base64.StdEncoding.EncodeToString(signData)

	encodedSignature := url.QueryEscape(signature)

	return encodedSignature, nil
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值