prometheus实战之五:飞书通知告警

news2025/1/17 4:46:59

欢迎访问我的GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos

《prometheus实战》系列链接

  1. prometheus实战之一:用ansible部署
  2. prometheus实战之二:使用常见指标
  3. prometheus实战之三:告警规则
  4. prometheus实战之四:alertmanager的部署和配置
  5. prometheus实战之五:飞书通知告警

本篇概览

  • 本文是《prometheus实战》系列的第五篇,主要内容是完成任务:应用服务器CPU使用率偏高时,飞书APP收到告警通知,完整的数据流如下图
    在这里插入图片描述

  • 前文的进度是完成了上图的绿色部分,今天要做的就是完成红色部分,让完整的功能可以使用

  • 前文咱们部署好了alertmanager,也在alertmanager上配置了告警时的webhook地址,然后还触发告警试了一下,不过由于webhook地址对应的服务并不存在,于是alertmanager调用失败,通过日志咱们观察到以下错误

May 13 10:04:40 deskmini alertmanager[767]: ts=2023-05-13T02:04:40.869Z caller=notify.go:732 level=warn component=dispatcher receiver=web.hook integration=webhook[0] msg="Notify attempt failed, will retry later" attempts=1 err="Post \"http://192.168.50.134:8888/webhook\": dial tcp http://192.168.50.134:8888/webhook: connect: connection refused"
May 13 10:09:40 deskmini alertmanager[767]: ts=2023-05-13T02:09:40.869Z caller=dispatch.go:352 level=error component=dispatcher msg="Notify for alerts failed" num_alerts=1 err="web.hook/webhook[0]: notify retry canceled after 16 attempts: Post \"http://192.168.50.134:8888/webhook\": dial tcp http://192.168.50.134:8888/webhook: connect: connection refused"
May 13 10:09:40 deskmini alertmanager[767]: ts=2023-05-13T02:09:40.869Z caller=notify.go:732 level=warn component=dispatcher receiver=web.hook integration=webhook[0] msg="Notify attempt failed, will retry later" attempts=1 err="Post \"http://192.168.50.134:8888/webhook\": dial tcp http://192.168.50.134:8888/webhook: connect: connection refused"
  • 今天的任务就是把这个web服务开发出来,并运行起来,这样整个功能就完善了

准备工作:飞书机器人

  • 本次实战打算用飞书作为通知消息的途径,因此要先把飞书机器人准备好,步骤如下
  • 先创建一个群聊在这里插入图片描述
  • 名称随意
    在这里插入图片描述
  • 点击设置
    在这里插入图片描述
  • 点击群机器人,打开群机器人设置页面
    在这里插入图片描述
  • 点击添加
    在这里插入图片描述
  • 选择自定义机器人
    在这里插入图片描述
  • 对机器人的名称和描述做简单的说明
    在这里插入图片描述
  • 如下图,页面会给出这个机器人唯一的webhook地址,也就是说,只要向这个地址发送请求,机器人就会发言,内容就是请求body
    在这里插入图片描述
  • 把上面的webhook地址准备好,稍后编码的时候会用到
  • 机器人已经准备好了,接下来开始编码
  • 这里要声明一下,选用飞书机器人,仅仅是欣宸个人觉得它简单方便,您完全可以按自己喜好选择其他通知途径

源码下载

  • 接下来要开发web服务,如果您不想写代码,可以在下面的仓库下载完整源码,更换飞书机器人的webhook地址后即可正常使用:
名称链接备注
项目主页https://github.com/zq2599/blog_demos该项目在GitHub上的主页
git仓库地址(https)https://github.com/zq2599/blog_demos.git该项目源码的仓库地址,https协议
git仓库地址(ssh)git@github.com:zq2599/blog_demos.git该项目源码的仓库地址,ssh协议
  • 这个git项目中有多个文件夹,本篇的文件在tutorials/prometheus/webhook/文件夹下,如下图红框所示:
    在这里插入图片描述

开发web服务,梳理开发步骤

  • 本篇打算使用go语言来开发web服务,web框架选用的是hertz,其实这不重要,您可以选择自己擅长的语言和框架来完成
  • 之所以用hertz,是因为它提供了命令可以快速创建工程,仅此而已
  • 动手写代码之前,先梳理好编码的具体步骤
1. 创建工程
2. 搭好web框架
3. 定义数据结构:alertmanager的请求体
4. 定义数据结构:飞书消息的请求体和响应
5. 转换器,将alertmanager请求体转换为飞书请求体
6. 主逻辑,收到alertmanager请求时向飞书发请求
7. 路由配置,将web path和主逻辑绑定
  • 接下来的操作就按照上述步骤进行,先来创建web工程吧

创建web工程

  • 再次强调,这里的web服务只是个helloworld级别的小工程,不论用什么语言什么框架都无所谓,您完全可以随心所欲
  • 接下来介绍我这边的开发步骤,请确保本地golang已经部署成功,并且将$GOPATH/bin添加到 PATH 环境变量之中(例如 export PATH=$GOPATH/bin:$PATH)
  • 首先是安装hertz,请确保本地golang已经部署成功,执行以下命令
go install github.com/cloudwego/hertz/cmd/hz@latest
  • 新建名为webhook的文件夹,在里面执行以下命令就会创建名为webhook的web工程
hz new -module webhook
  • 下载依赖包
go mod tidy
  • 此时再看webhook目录,整个代码框架已经准备好了,接下来只要把业务代码填上去即可
tree webhook                                      
webhook
├── biz
│   ├── handler
│   │   └── ping.go
│   └── router
│       └── register.go
├── build.sh
├── go.mod
├── main.go
├── router_gen.go
├── router.go
└── script
    └── bootstrap.sh

编码,alertmanager请求体定义

  • 先定义model,这是接受alertmanager请求的数据结构,新建文件webhook/biz/model/alert.go
package model

import "time"

type Alert struct {
	Labels      map[string]string `json:"labels"`
	Annotations map[string]string `json:annotations`
	StartsAt    time.Time         `json:"startsAt"`
	EndsAt      time.Time         `json:"endsAt"`
}

type Notification struct {
	Version           string            `json:"version"`
	GroupKey          string            `json:"groupKey"`
	Status            string            `json:"status"`
	Receiver          string            `json:receiver`
	GroupLabels       map[string]string `json:groupLabels`
	CommonLabels      map[string]string `json:commonLabels`
	CommonAnnotations map[string]string `json:commonAnnotations`
	ExternalURL       string            `json:externalURL`
	Alerts            []Alert           `json:alerts`
}

编码,飞书消息的请求和响应

  • 由于要请求飞书服务器,因此请求和响应的数据结构也要定义好,新建文件webhook/biz/model/lark.go
package model

// 飞书机器人支持的POST数据结构
// 请求体相关
type LarkRequest struct {
	MsgType string  `json:"msg_type"`
	Content Content `json:"content"`
}
type Content struct {
	Text string `json:"text"`
}

// 响应体相关
type LarkResponse struct {
	Code int    `json:"code"`
	Msg  string `json:"msg"`
	Data Data   `json:"data"`
}
type Data struct {
}

编码,alertmanager到飞书请求体的转换工具

  • 收到alertmanager请求后,要把有效内容转换成飞书请求体,这里做一个转换工具,新建文件webhook/biz/util/lark_transformer.go
package util

import (
	"bytes"
	"fmt"
	"webhook/biz/model"
)

// TransformToLarkRequest 根据alertmanager的对象,创建出飞书消息的对象
func TransformToLarkRequest(notification model.Notification) (larkRequest *model.LarkRequest, err error) {
	var buffer bytes.Buffer

	// 先拿到分组情况
	buffer.WriteString(fmt.Sprintf("通知组%s,状态[%s]\n告警项\n\n", notification.GroupKey, notification.Status))

	// 每条告警逐个获取,拼接到一起
	for _, alert := range notification.Alerts {
		buffer.WriteString(fmt.Sprintf("摘要:%s\n详情:%s\n", alert.Annotations["summary"], alert.Annotations["description"]))
		buffer.WriteString(fmt.Sprintf("开始时间: %s\n\n", alert.StartsAt.Format("15:04:05")))
	}

	// 构造出飞书机器人所需的数据结构
	larkRequest = &model.LarkRequest{
		MsgType: "text",
		Content: model.Content{
			Text: buffer.String(),
		},
	}

	return larkRequest, nil
}

编码:主逻辑

  • 数据结构和工具方法都准备好了,接下来就是主逻辑:收到alertmanager的请求后,根据请求体转为飞书消息请求体,再向飞书发送请求

  • 接着是响应请求的handler,新建文件webhook/biz/handler/alertmanager.go

// Code generated by hertz generator.

package handler

import (
	"bytes"
	"context"
	"encoding/json"
	"io"
	"net/http"
	"webhook/biz/model"
	"webhook/biz/util"

	"github.com/cloudwego/hertz/pkg/app"
	"github.com/cloudwego/hertz/pkg/common/hlog"
	"github.com/cloudwego/hertz/pkg/common/utils"
	"github.com/cloudwego/hertz/pkg/protocol/consts"
)

const (
	// 请使用您自己的机器人的webhook地址
	LARK_URL = "https://open.feishu.cn/open-apis/bot/v2/hook/12345678-1234-1234-1234-123456789012"
)

// Ping .
func AlertmanagerWebhook(ctx context.Context, c *app.RequestContext) {
	var notification model.Notification

	// 绑定对象
	err := c.BindAndValidate(&notification)
	if err != nil {
		c.JSON(consts.StatusBadRequest, utils.H{
			"error": err.Error(),
		})

		return
	}

	hlog.Info("收到alertmanager告警:\n%s", notification)

	// 根据alertmanager的请求构造飞书消息的请求数据结构
	larkRequest, _ := util.TransformToLarkRequest(notification)

	// 向飞书服务器发送POST请求,将飞书服务器返回的内容转为对象
	bytesData, _ := json.Marshal(larkRequest)
	req, _ := http.NewRequest("POST", LARK_URL, bytes.NewReader(bytesData))
	req.Header.Add("content-type", "application/json")
	res, err := http.DefaultClient.Do(req)
	// 飞书服务器可能通信失败
	if err != nil {
		hlog.Error("请求飞书服务器失败:%s", err)
		c.JSON(consts.StatusInternalServerError, utils.H{
			"error": err.Error(),
		})

		return
	}
	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)
	var larkResponse model.LarkResponse
	err = json.Unmarshal([]byte(body), &larkResponse)
	// 飞书服务器返回的包可能有问题
	if err != nil {
		hlog.Error("获取飞书服务器响应失败:%s", err)
		c.JSON(consts.StatusInternalServerError, utils.H{
			"error": err.Error(),
		})

		return
	}
	hlog.Info("向飞书服务器发送消息成功")
	c.JSON(consts.StatusOK, utils.H{
		"message": "successful receive alert notification message!",
	})
}
  • 编码结束,可以运行起来试试了

vscode配置

  • 如果您的IDE是vscode,将launch.json写成下面这样,就能在vscode启动这个项目了
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Launch Package",
            "type": "go",
            "request": "launch",
            "mode": "auto",
            "program": "${workspaceFolder}"
        }
    ]
}

shell脚本配置

  • 如果想在linux下编译、构建、运行,可以用hertz准备好的shell脚本,不过要先做一点修改
  • 打开script/bootstrap.sh,内容如下
#!/bin/bash
CURDIR=$(cd $(dirname $0); pwd)
BinaryName=
echo "$CURDIR/bin/${BinaryName}"
exec $CURDIR/bin/${BinaryName}
  • 上述内容中BinaryName变量没有值,这会导致运行程序时找不到二进制文件,这里给它加上,修改后如下
#!/bin/bash
CURDIR=$(cd $(dirname $0); pwd)
BinaryName=webhook
echo "$CURDIR/bin/${BinaryName}"
exec $CURDIR/bin/${BinaryName}
  • 现在可以用现成的shell编译和运行项目了
  • 构建命令是sh build.sh
  • 启动命令是sh output/bootstrap.sh

验证

  • 将web服务运行起来,确保其地址和alertmanager配置的一致

  • 想办法触发告警,我这里是用ffmpeg使得应用服务器CPU使用类升高,如下图,prometheus的告警进入Firing状态
    在这里插入图片描述

  • alertmanager收到告警
    在这里插入图片描述

  • 很快,飞书消息也到达了,内容符合预期
    在这里插入图片描述

  • 想办法让应用服务器退出告警状态,我这里是杀掉ffmpeg进程,让应用服务器的CPU回到正常状态
    在这里插入图片描述

  • 很快,飞书的第二条消息到来,状态是resolved,表示应用服务器已经退出告警状态
    在这里插入图片描述

  • 两条告警消息的间隔是5分钟,这和alertmanager的配置有关,如下图,group_interval表示5分钟内不在firing状态,就表示故障已恢复
    在这里插入图片描述

  • 至此,从部署到配置,再到最终飞书通知,整个告警的流程咱们都动手实现了,希望这一系列实战操作能给您一些参考,助您搭建出匹配业务的告警系统

你不孤单,欣宸原创一路相伴

  1. Java系列
  2. Spring系列
  3. Docker系列
  4. kubernetes系列
  5. 数据库+中间件系列
  6. DevOps系列

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/524025.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Day968.如何开启一个遗留系统现代化项目? -遗留系统现代化实战

如何开启一个遗留系统现代化项目? Hi,我是阿昌,今天学习记录的是关于如何开启一个遗留系统现代化项目?的内容。那如何启动一个遗留系统现代化项目。 一、项目背景 说来有点唏嘘,国内遗留系统的重灾区,恰恰…

MongoDB概念和操作

一、相关概念 在mongodb中最基本的概念为:文档、集合、数据库 SQL术语/概念MongoDB术语/概念解释/说明databasedatabase数据库tablecollection数据库表/集合rowdocument数据记录行/文档columnfield数据字段/域indexindex索引table joins表连接,MongoDB不支持prima…

Cordova webapp实战开发:(5)如何写一个Andorid下自动更新的插件?

在 《Cordova webapp实战开发:(4)Android环境搭建》中我们搭建好了开发环境,也给大家布置了调用插件的预习作业,做得如何了呢?今天我们来学一下如何自己从头建立一个Andorid下的cordova插件。 本次练习你能…

【大腹太卷】一篇文章带你了解校招的神秘面纱

校招求职复盘 写在前面方向确定前置工作就业信息获取简历制作简历投递 笔面试工作测评笔试面试八股文自我介绍项目相关HR面试反问环节 Offer选择写在后面 写在前面 2023届应届生,去年的时候参加了校招,一路走来,感慨良多,特此记录…

蚊香液、蚊香片、蚊香盘的优缺点

夏天来了,蚊子也出来活动了,又到了消灭蚊子的季节。     蚊子是凭借人所呼出的二氧化碳和带气味的气体,来定位人的位置,进而叮咬人的皮肤。     蚊子吸人血,主要是利用血液里的胆固醇、B族维生素,促进蚊…

OSPF综合实验(第一部分)

目录 要求 确定广播域的个数 分配网段 配置路由器IP地址-优先公网配通 配置MGRE部分 拓扑结构: 要求 1、R4为ISP,其上只能配置IP地址,R4与其他所有直连设备间使用公有IP 2、R3~R5/6/7为MGRE环境,R3为中心站点 3、整个OSPF环境I…

《编程思维与实践》1072.下一位妙数

《编程思维与实践》1072.下一位妙数 题目 思路 思路与最小不重复数基本一致,从最高位开始找到第一个出现9的位置,让其加1,后面全变为0即可. 只需要再加一个判定条件:不能被9整除. 由数学知识,一个数不能被9整除当且仅当各位数之和不能被9整除. 这里给出简单的证明: 不妨以三位…

Linux-初学者系列7_shell编程

在进行服务器集群管理时,需要编写shell程序来进行服务器管理。 shell是一个命令行解释器,他会为用户提供了一个向Linux内核发送请求以便运行程序的界面系统级程序,用户用shell启动、挂起、停止和编写一些程序。 Linux-初学者系列7_shell编程…

简单记录一下spi的四种mode

0 前言 最近在学习SPI&#xff0c;刚开始接触四种mode的时候&#xff0c;还有点懵&#xff0c;也是搜了好几个博客&#xff0c;才算搞懂&#xff0c;特此记录下&#xff0c;防止下次又要翻好几篇博客才找到答案 >_< 1 四种mode的组成单元 这四种mode是由时钟极性和时钟…

Leetcode刷题之反转链表Ⅱ

业精于勤而荒于嬉&#xff0c;行成于思而毁于随。 ——韩愈目录 前言&#xff1a; &#x1f341;一.反转链表Ⅱ &#x1f352;1.left和right中间链表反转&#xff0c;再把反转链表和剩下的链接起来 &#x1f5fc;2.left和right中间链表头插 题目描述…

「实验记录」MIT 6.824 Raft Lab2A Leader Election

#Lab2A - Leader Election I. SourceII. My CodeIII. MotivationIV. SolutionS1 - 角色转换S2 - 发起 RequestVote 拉票请求S3 - 收到 RequestVote 的不同反应S4 - 发送 AppendEntries 心跳包S5 - 收到 AppendEntries 的不同反应S6 - defs.go约定俗成和GetState() V. Result I.…

The service already exists!

文章目录 项目场景&#xff1a;原因分析&#xff1a;解决方案&#xff1a; 项目场景&#xff1a; 提示&#xff1a;这里简述项目相关背景&#xff1a; 在给一位同学安装MySQL时报了这个错&#xff0c;我知道是她之前安装过但是没删干净的原因 但是我把Everything和注册表都查…

五、RGB实验(正点原子达芬奇Pro代码>>ZYNQ 7020代码移植)

RGB实验(正点原子达芬奇Pro代码&#xff1e;&#xff1e;ZYNQ 7020代码移植) 文章目录 RGB实验(正点原子达芬奇Pro代码&#xff1e;&#xff1e;ZYNQ 7020代码移植)前言一、本文目标二、移植步骤1.建立文件2.建立v文件1.lcd_rgb_colorbar2.lcd_driver3.rd_id4.clk_div5.lcd_dis…

单调队列算法模板及应用

文章和代码已经归档至【Github仓库&#xff1a;https://github.com/timerring/algorithms-notes 】或者公众号【AIShareLab】回复 算法笔记 也可获取。 文章目录 队列算法模板例题&#xff1a;滑动窗口code 队列算法模板 // hh 表示队头&#xff0c;tt表示队尾 int q[N], hh 0…

使用Advanced Installer软件将winform程序打包成exe安装文件

在使用vs编写c#代码时&#xff0c;一般都是在debug文件中双击exe文件就可以执行&#xff0c;但是有时候需要将这个exe文件发给别人使用&#xff0c;在自己的电脑上exe文件可以执行&#xff0c;但是在别人的电脑上有时候打开后会报错&#xff0c;提示缺少.neta运行环境&#xff…

AUTUSAR通信篇 - CAN网络通信(一)

第一篇从全局角度出发&#xff0c;简单介绍了AUTOSAR的结构&#xff0c;从本篇开始我们一起详细了解一下AUTOSAR软件架构下内部的组成部分。下面&#xff0c;我们首先介绍第一个模块-通信。在AUTOSAR BSW中通信由三个部分组成&#xff0c;分别是&#xff1a;通信驱动、通信抽象…

【计算机视觉 | Pytorch】timm 包的具体介绍和图像分类案例(含源代码)

一、具体介绍 timm 是一个 PyTorch 原生实现的计算机视觉模型库。它提供了预训练模型和各种网络组件&#xff0c;可以用于各种计算机视觉任务&#xff0c;例如图像分类、物体检测、语义分割等等。 timm 的特点如下&#xff1a; PyTorch 原生实现&#xff1a;timm 的实现方式…

Java之线程池

目录 一.上节复习 1.阻塞队列 二.线程池 1.什么是线程池 2.为什么要使用线程池 3.JDK中的线程池 三.工厂模式 1.工厂模式的目的 四.使用线程池 1.submit()方法 2.模拟两个阶段任务的执行 五.自定义一个线程池 六.JDK提供线程池的详解 1.如何自定义一个线程池? 2.创…

【计网】第三章 数据链路层(3)信道划分介质访问控制

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 3.5-1 信道划分介质访问控制&#xff08;播报信道中应用&#xff09;一、传输数据使用的两种链路二、介质访问控制 三、信道划分 介质访问控制&#xff08;静态划分…

协程切换原理与实践 -- 从ucontext api到x86_64汇编

目录 1.协程切换原理理解 2.ucontext实现协程切换 2.1 实现流程 2.2 根据ucontext流程看协程实现 2.3 回答开头提出的问题 3.x86_64汇编实现协程切换 3.1libco x86_64汇编代码分析 3.2.保存程序返回代码地址流程 3.3.恢复程序地址以及上下文 4.实现简单协程框架 1.协程…