当前位置: 首页 > news >正文

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

欢迎访问我的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 modelimport "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 utilimport ("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 handlerimport ("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.LarkResponseerr = 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系列

相关文章:

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

欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 《prometheus实战》系列链接 prometheus实战之一:用ansible部署prometheus实战之二:使用常见指标prometheus实战之三:告警…...

【华为OD机试真题】不含101的数(python版)100%通过率 超详细代码注释 代码解读

【华为OD机试真题 2022&2023】真题目录 @点这里@ 【华为OD机试真题】信号发射和接收 &试读& @点这里@ 【华为OD机试真题】租车骑绿道 &试读& @点这里@ 不含101的数 时间限制:1s空间限制:256MB限定语言:不限 题目描述: 小明在学习二进制时,发现了一…...

基于AT89C52单片机的交通信号灯设计

点击链接获取Keil源码与Project Backups仿真图: https://download.csdn.net/download/qq_64505944/87772657 源码获取 主要内容: 本次设计所提出的一种基于单片机技术的简易计算器的方案,能更好的解决计算机计算的问题,随着数字生活的到来&…...

chatGPT4.0-基于Python+Appium的APPUI关键字驱动自动化测试框架demo

以下是一个简单的UI关键字驱动+数据驱动的自动化测试框架代码示例,使用Python和Appium进行移动应用测试。我们将使用openpyxl库读取Excel数据,使用Appium-Python-Client库进行UI自动化测试。 首先,请确保已安装以下库: pip install openpyxl pip install Appium-Python-C…...

C++模板进阶

一、非类型模板参数 模板参数分为&#xff1a;类型形参、非类型形参 类型形参&#xff1a;class与typename都是参数类型 非类型形参&#xff1a;用一个常量作为模板的一个参数&#xff0c;一般是整型常量 #include<iostream> #include<array> using namespace …...

【人力资源管理】第4集 免费开源ERP: Odoo 16 Appraisal员工绩效评估 构建一体化企业人力资源管理

文章目录 前言一、概览二、主要功能1.设置定期的员工评估2.构建正确的评估3.设计您自己的调查4.自动评估过程 总结 前言 在员工工作中创建评估。同时审查员工表现。 一、概览 员工评价 评估内容 目标制定 评价指标 评价分析 二、主要功能 1.设置定期的员工评估 强化贵公司的…...

「AI 孙燕姿」翻唱华语乐坛歌曲爆红全网,AI 翻唱将带来哪些影响?是否会有版权等问题?

在某视频平台上&#xff0c;“AI孙燕姿”成了新网红&#xff0c;它翻唱过周杰伦的《发如雪》、翻唱过郭顶的《水星记》、翻唱过赵雷的《我记得》&#xff0c;受到了网友的追捧&#xff0c;甚至有网友宣布“这是2023年最火的声音”。 网上除了AI孙燕姿&#xff0c;还有AI周杰伦…...

路径规划算法:基于灰狼优化的路径规划算法- 附代码

路径规划算法&#xff1a;基于灰狼优化的路径规划算法- 附代码 文章目录 路径规划算法&#xff1a;基于灰狼优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要&#xff1a;本文主要介绍利用智能优化算法灰狼…...

推荐系统综述

目录 推荐系统架构1、传统推荐方式1.1 基于内容推荐&#xff08;Content-Based recommendation&#xff0c;CB&#xff09;1.2 协同过滤推荐&#xff08;Collaborative Filtering recommendation&#xff0c; CF&#xff09;1.2.0 UserCF举例&#xff1a;1. 2. 1 基于内存的推荐…...

SQLIST数据库编程

目录 数据库简介 1.常用数据库 2. SQLite基础 3.创建SQLite数据库 虚拟中sqlite3安装 基础SQL语句使用 sqlite3编程 数据库简介 1.常用数据库 大型数据库 &#xff1a;Oracle 中型数据库 &#xff1a;Server是微软开发的数据库产品&#xff0c;主要支持windows平台 小型数据库…...

vue2中操作对象的方法

在 Vue2 中&#xff0c;我们可以使用以下方法来操作对象&#xff1a; Vue.set(object, key, value)&#xff1a;用于在 Vue 实例中添加响应式属性。它会确保添加的属性是响应式的&#xff0c;并触发视图更新。 Vue.delete(object, key)&#xff1a;用于从 Vue 实例中删除属性。…...

左值引用、右值引用,std::move() 的汇编解释

1&#xff1a;左值引用 引用其实还是指针&#xff0c;但回避了指针这个名字。由编译器完成从地址中取值。以vs2019反汇编&#xff1a; 如图&#xff0c;指针和引用的汇编代码完全一样。但引用在高级语言层面更友好&#xff0c;对人脑。比如可以少写一个 * 号和 -> 。 &…...

LiangGaRy-学习笔记-Day11

LiangGaRy-学习笔记-Day11 1、课前回顾 1.1、脚本回顾讲解 题目&#xff1a; 脚本实现搭建LAMP架构可以写一段&#xff0c;后试一段引入变量、函数、尝试增删改查手工执行一遍 [rootNode1 ~]# vim auto_lanmp.sh #!/bin/bash #Author By LiangGaRy #2023年5月7日 #Usage …...

【异常解决】浏览器无法访问此网站ERR_UNSAFE_PORT/网页可能无法连接,或者它已永久性地移动到了新网址问题解决方案

浏览器无法访问此网站ERR_UNSAFE_PORT问题解决方案 一、问题描述二、问题原因三、解决方案3.1 方案1修改服务器访问端口号&#xff08;推荐&#xff09;3.2 方案2修改浏览器设置3.2.1 Chrome浏览器3.2.2 Firefox浏览器3.2.3 Edge浏览器 一、问题描述 访问某一个特定的网址之后…...

Python函数的参数

定义一个函数非常简单&#xff0c;但是怎么定义一个函数&#xff0c;需要什么参数&#xff0c;怎么去调用却是我们需要去思考的问题。 如同大多数语言一样&#xff08;如 Java&#xff09;&#xff0c;Python 也提供了多种参数的设定&#xff08;如&#xff1a;默认值参数、关…...

【Hive大数据】Hive分区表与分桶表使用详解

目录 一、分区概念产生背景 二、分区表特点 三、分区表类型 3.1 单分区 3.2 多分区 四、动态分区与静态分区 4.1 静态分区【静态加载】 4.1.1 操作演示 4.2 多重分区 4.2.1 操作演示 4.3 分区数据动态加载 4.3.1 分区表数据加载 -- 动态分区 4.3.2 操作演示 五、…...

C#NPOI操作Excel详解

C# NPOI 是一个基于 .NET Framework 的 Excel 和 Word 操作库。它不仅可以读取和写入 Excel 和 Word 文件&#xff0c;还可以对 Excel 和 Word 文件进行格式化和样式编辑&#xff0c;支持多种常见的文件格式&#xff0c;如XLS&#xff0c;XLSX等。本篇文章将针对C# NPOI操作Exc…...

CSS中文字体 Unicode 编码表

一、简介 CSS&#xff08;层叠样式表&#xff09;是用于样式化Web页面的强大工具&#xff0c;它可以用来控制页面的外观和行为。在CSS中&#xff0c;可以使用多种字体来设置文本的外观和格式&#xff0c;包括中文字体。中文字体的实现需要引入相应的字体文件&#xff0c;并且需…...

《微服务实战》 第四章 Spring Cloud Netflix 之 Eureka

前言 Eureka 是 Netflix 公司开发的一款开源的服务注册与发现组件。 Spring Cloud 使用 Spring Boot 思想为 Eureka 增加了自动化配置&#xff0c;开发人员只需要引入相关依赖和注解&#xff0c;就能将 Spring Boot 构建的微服务轻松地与 Eureka 进行整合。 1、Eureka 两大组…...

11. 深入理解并发编程-AQS与JMM

AQS (AbstractQueuedSynchronizer) 他的实现类诸如: CountDownLatch、ThreadLocalPool和ReentrantLock 在这些类中,AQS都是以内部类的形式存在的 AQS使用了模板方法设计模式 例子: 做蛋糕分为3个步骤,定一个抽象类,重写3个方法,做模型、烘焙和涂抹原料,然后在另外1个方法做蛋糕…...

深度解耦:使用Jetpack新技术Hilt实现依赖注入

注入解耦是一种软件设计模式&#xff0c;旨在将应用程序的不同组件解耦。通过采用依赖注入、控制反转、面向接口编程等技术&#xff0c;注入解耦模式可以帮助开发人员将应用程序分解为可重用和可扩展的组件。这样做可以减少代码的耦合度&#xff0c;提高模块化和可测试性&#…...

C++ 构造函数-2

构造函数-2 构造函数体赋值 在对象创建的时候&#xff0c;编译器会调用构造函数&#xff0c;给对象当中的成员赋一个合适的初始值。 class Date { public: Date(int year, int month, int day) { _year year; _month month; _day day; } private: int _year; int _month; i…...

网安笔记 08 key management

Key Management —— 不考 网络加密方法 1.1 链路加密 特点&#xff1a; 两个相邻点之间数据进行加密保护 不同节点对密码机和Key不一定同中间节点上&#xff0c;先解密后加密报文报头可一起加密节点内部&#xff0c;消息以明文存在密钥分配困难保密及需求数量大 缺点&…...

Linux socket

百度百科对于Socket的介绍 套接字&#xff08;socket&#xff09;是一个抽象层&#xff0c;应用程序可以通过它发送或接收数据&#xff0c;可对其进行像对文件一样的打开、读写和关闭等操作。套接字允许应用程序将I/O插入到网络中&#xff0c;并与网络中的其他应用程序进行通信…...

14.构造器的排序分组.子查询

学习要点&#xff1a; 1.排序分组 2.子查询 本节课我们来开始学习数据库的构造器查询中的子查询、排序、分组等。 一&#xff0e;排序分组 1. 使用 whereColumn()方法实现两个字段相等的查询结果&#xff1b; //判断两个相等的字段&#xff0c;同样支持 orWhereColumn() //支持…...

【剑指 Offer】05,替换字符创中的空格;难度等级:简单。易错点:C++中 char 和 string 类型的转换

【剑指 Offer】05&#xff0c;替换字符创中的空格&#xff1b;难度等级&#xff1a;简单。 文章目录 一、题目二、题目背景三、我的解答四、易错点五、知识点&#xff1a;char 和 string 类型的转换 一、题目 二、题目背景 在网络编程中&#xff0c;如果 URL 参数中含有特殊字…...

图像分割入门教程

文章目录 图像分割入门教程1. 图像分割基本概念2. 基于阈值的图像分割3. 基于区域的图像分割4. 基于边缘的图像分割5. 基于区域和边缘的图像分割区别6. 基于深度学习的图像分割7. 实现步骤结论 图像分割入门教程 图像分割是计算机视觉领域的一个重要任务&#xff0c;其目标是将…...

C++入门教程||C++ 信号处理||C++ 多线程

C 信号处理 C 信号处理 信号是由操作系统传给进程的中断&#xff0c;会提早终止一个程序。在 UNIX、LINUX、Mac OS X 或 Windows 系统上&#xff0c;可以通过按 CtrlC 产生中断。 有些信号不能被程序捕获&#xff0c;但是下表所列信号可以在程序中捕获&#xff0c;并可以基于…...

java计算矩形的面积和周长的方法

在生活中&#xff0c;我们常常需要计算某个矩形的面积和周长&#xff0c;如我们经常用的计算器就是个不错的选择&#xff0c;它可以计算出任意一个矩形的面积和周长。那么&#xff0c;如果你想使用 Java编程语言来计算矩形的面积和周长&#xff0c;你该如何做呢&#xff1f;今天…...

一分钟掌握如何更换Jupyter Notebook的主题和字体

Jupyter Notebook 更换主题&#xff08;背景、字体&#xff09; 在现代科技发展的浪潮中&#xff0c;Jupyter Notebook 作为一种强大的交互式笔记工具&#xff0c;已经被越来越多的用户所使用。它以其简单易用、功能强大、资源丰富等特点&#xff0c;成为了许多人学习、工作、科…...