飞书告警实践
在上一篇中我们完整实践了整个 Prometheus 监控体系是怎么玩儿的,关于告警信息的发送我们只是简单的将告警信息打印在屏幕中,有了一个直观的了解,但是在真正的业务场景中,是需要将告警信息发送给具体的告警接收人的,所以这一篇,我们开发个简单的 webhook 服务,来将告警信息通过飞书的方式发送。
新建飞书 Robot
需要新建一个飞书群组
在飞书群组中新建一个飞书 Robot
拿到飞书 Robot 的 Webhook 地址,接下来的开发中会用到这个 Webhook 地址
开发一个 Webhook 服务
基于飞书卡片模版,来开发 Webhook 服务
启动服务 go run main.go
点击查看代码
package main
import (
"bytes"
"encoding/json"
"fmt"
"log"
"net/http"
"time"
)
type AlertMsg struct {
Receiver string
Status string
GroupLabels map[string]string
CommonLabels map[string]string
CommonAnnotations map[string]string
ExternalURL string
Alerts []Alert
}
type Alert struct {
Status string
Labels map[string]string
Annotations map[string]string
StartsAt time.Time
EndsAt time.Time
GeneratorURL string
Fingerprint string
}
type FeishuMsg struct {
Card MsgCard `json:"card"`
MsgType string `json:"msg_type"`
}
type MsgCard struct {
Header CardHeader `json:"header"`
Elements []CardElement `json:"elements"`
}
type CardHeader struct {
Template string `json:"template"`
Title ContentTag
}
type ContentTag struct {
Content string `json:"content"`
Tag string `json:"tag"`
}
type CardElement struct {
Tag string `json:"tag"`
Fields []FieldContent `json:"fields"`
}
type FieldContent struct {
IsShort bool `json:"is_short"`
Text ContentTag `json:"text"`
}
const Webhook = "https://open.feishu.cn/open-apis/bot/v2/hook/e6e55b00-8782-43a2-9cf4-a6fcf1b6aef4"
func main() {
http.HandleFunc("/alerts", alertHandler)
log.Fatal(http.ListenAndServe("0.0.0.0:5001", nil))
}
func alertHandler(w http.ResponseWriter, r *http.Request) {
dec := json.NewDecoder(r.Body)
defer r.Body.Close()
var m AlertMsg
if err := dec.Decode(&m); err != nil {
log.Printf("decoding alert message error: %v", err)
return
}
for _, alert := range m.Alerts {
var feishu_msg FeishuMsg
feishu_msg.MsgType = "interactive"
// 告警消息
if alert.Status == "firing" {
feishu_msg.Card.Header.Template = "red"
feishu_msg.Card.Header.Title.Content = fmt.Sprintf("崩盘 - %s", alert.Labels["_product_name"])
feishu_msg.Card.Header.Title.Tag = "plain_text"
content := fmt.Sprintf(
"**告警名称**: %s\n**告警时间**: %s\n**告警概述**: %s\n**告警产品**: %s\n**告警实例**: %s\n",
alert.Labels["alertname"],
alert.StartsAt.UTC().Format("2006-01-02 15:04:05"),
alert.Annotations["summary"],
alert.Labels["_product_name"],
alert.Labels["_name"],
)
field := FieldContent{
IsShort: true,
Text: ContentTag{Tag: "lark_md", Content: content},
}
fields := make([]FieldContent, 0)
fields = append(fields, field)
element := CardElement{
Tag: "div",
Fields: fields,
}
elements := make([]CardElement, 0)
elements = append(elements, element)
feishu_msg.Card.Elements = elements
} else {
// 恢复消息
feishu_msg.Card.Header.Template = "green"
feishu_msg.Card.Header.Title.Content = fmt.Sprintf("恢复 - %s", alert.Labels["_product_name"])
feishu_msg.Card.Header.Title.Tag = "plain_text"
content := fmt.Sprintf(
"**告警名称**: %s\n**恢复时间**: %s\n**告警概述**: %s\n**告警产品**: %s\n**告警实例**: %s\n",
alert.Labels["alertname"],
alert.EndsAt.UTC().Format("2006-01-02 15:04:05"),
alert.Annotations["summary"],
alert.Labels["_product_name"],
alert.Labels["_name"],
)
field := FieldContent{
IsShort: true,
Text: ContentTag{Tag: "lark_md", Content: content},
}
fields := make([]FieldContent, 0)
fields = append(fields, field)
element := CardElement{
Tag: "div",
Fields: fields,
}
elements := make([]CardElement, 0)
elements = append(elements, element)
feishu_msg.Card.Elements = elements
}
msg_body, err := json.Marshal(feishu_msg)
if err != nil {
log.Fatalf("json marshal feishu_msg error: %v", err)
}
req, err := http.NewRequest("POST", Webhook, bytes.NewBuffer(msg_body))
req.Header.Set("Content-Type", "application/json")
if err != nil {
log.Fatalf("http new request error: %v", err)
}
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Fatalf("post feishu_msg error: %v", err)
}
defer resp.Body.Close()
}
}
查看飞书告警信息
飞书群组接收到的告警信息如图
下面我们测试下告警恢复的消息,先把 node exporte 关闭再开启,这样就模拟了监控对象的离线和在线
结语
这里我们只是简单的实践了通过飞书的机器人来发送告警消息,还没有深入的开发。如:
- 告警消息很多的情况下,怎么发送告警信息,因为如果还是一条条发送的话,会面临告警风暴
- 不同的人需要接收到不同的告警消息,那么我们的后端服务就需要一个接收者列表,当发送消息的时候去请求指定的 Webhook 地址
- 飞书的消息卡片支持回调,当我们收到告警卡片信息的时候,可以有按钮点击设置当前告警的维护