# prometheus-spring-boot-starter
**Repository Path**: gitxuchang/prometheus-spring-boot-starter
## Basic Information
- **Project Name**: prometheus-spring-boot-starter
- **Description**: 一个管理异常通知的神奇starter,实现了钉钉消息提醒与邮件提醒,同时加入了微服务的服务异常提醒
- **Primary Language**: Java
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 230
- **Created**: 2022-08-11
- **Last Updated**: 2022-08-11
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 一个异常通知的spring-boot-start框架 prometheus-spring-boot-starter
#### 更新预告
2021-10-15 团队版准备更新到0.7.0-team,主要更新的是各个模块组件化,同时加入个人版中的微服务通知体系,目前代码进入测试阶段,readme暂时没有更新,有想帮忙更新的小伙伴可以留言[https://gitee.com/ITEater/prometheus-spring-boot-starter/tree/team-0.7.0/](https://gitee.com/ITEater/prometheus-spring-boot-starter/tree/team-0.7.0/)
#### 前言的前言:
- 个人用异常通知请移步:[个人版分支](https://gitee.com/ITEater/prometheus-spring-boot-starter/tree/personal/)
- 多人协作开发需要异常通知请移步:[团队版分支](https://gitee.com/ITEater/prometheus-spring-boot-starter/tree/team/)
## 2020-11-03更新(大更新)
1. 新增:微服务监控通知
2. 改造:现有的大部分配置以改变,无法与之前的版本兼容
3. 改造:httpclient已换成feign框架
4. 改进:现有所有功能编程可插拔的模块化设计
5. 改进:异常接收后的处理变成了event处理
6. 版本号正式升级为**0.6.0-persional**
## 2020-03-22更新(个人版更新)
1. 新增:包含现有团队版的所有功能
2. 改进:调整了内部ExceptionNoticeResolver的叫法
3. 改进:异常通知的存储方式
## 2020-01-03更新(大更新)
1. 版本号正式升级为**0.5.1-team**
2. 新增:**异步通知**
3. 新增:异常通知文本结构自定义
4. 新增:异常通知的**环境类型**
5. 新增:钉钉的**markdown文本支持**
6. 新增:**钉钉的加签验证**
7. 改进:自定义钉钉通知流程
8. 改进:config自动化配置
9. 改进:钉钉的调用所需的HTTPclient可自行配置,默认配置改为spring中resttemplate,原来的SimpleHttpclient已被废弃,这意味着依赖中需要spring-boot-starter-web
10. 改进:对于异常信息中caused by进行了处理
11. 修复bug
## 2019-06-24更新
1. 改进:web处理增加一个拦截器,专门清除为异常通知保存的请求体信息
2. 修复bug:修复了初次出现异常产生的并发导致重复发送的问题
3. 当前版本号变为**0.3.5-team**
## 前言
对于工程的开发,必然会伴随着各种bug,工程量越大,出现bug的概率也会越高。一般对于代码量较小的工程来说,一个人可能就足够去做开发与维护;但是对于代码量较大的工程往往是需要一个小团队协作开发。当工程基本完成,开始部署测试环境或者生产环境时,这些环境并不能像开发环境一样能快速的调试与维护,线上的工程一旦出现异常时,开发团队就需要主动感知异常并协调处理,当然人不能一天24小时去盯着线上工程,所以就需要一种机制来自动化的对异常进行通知,并精确到谁负责的那块代码。这样会极大地方便后续的运维。因此,本项目上线
## 系统需求



## 当前版本

## 最快上手
- 将此工程通过``mvn clean install``打包到本地仓库中。
- 在你的工程中的``pom.xml``中做如下依赖
```
com.kuding
prometheus-spring-boot-starter
0.6.0-personal
```
- 在``application.properties``或者``application.yml``中做如下的配置:(至于以上的配置说明后面的章节会讲到)
```
prometheus:
enabled: true
dingding:
enabled: true
phone-num:
- 要@的人的手机号
access-token: 钉钉通知的所给的url的后面的accessToken的参数的值
sign-secret: 钉钉的签名秘钥
enable-signature-check: true
exceptionnotice:
enabled: true
included-trace-package: com.kuding
```
- 至于钉钉的配置请移步:[钉钉机器人](https://open-doc.dingtalk.com/microapp/serverapi2/krgddi "自定义机器人"),这里需要特别说明一下,钉钉在2019年10月份(大概)对于钉钉机器人进行了一次改进,这次改进主要是安全设置变为必选项,原来已经配置过的钉钉机器人且没有配置安全设置的不受影响

- 以上配置好以后就可以写demo测试啦,首先创建第一个bean:
```
@Component
@ExceptionListener // 异常通知的监控来自这个注解
public class NoticeComponents {
public void someMethod(String name) {
System.out.println("这是一个参数:" + name);
throw new NullPointerException("第一个异常");
}
public void anotherMethod(String name, int age) {
System.out.println("这又是一个参数" + age);
throw new IllegalArgumentException(name + ":" + age);
}
}
```
- 以上都建立好了以后,就可以写单元测试了:
```
@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {
@Autowired
private NoticeComponents noticeComponents;
@Test
public void contextLoads() {
noticeComponents.someMethod("hello");
}
}
```
当运行单元测试后,假如钉钉配置没有问题的话,你的钉钉中就会出现如下类似的消息:

假如在你配置的钉钉中出现类似这个信息的化,恭喜你,你成功的产生了一个异常通知。
- 综上,一个最简单的例子就完成了。
## 咋做的
本框架遵循spring boot starter的自动化配置规范而开发的自动化异常通知框架,整体业务流程如下:

### 配置
本框架配置主要分为4部分:
1. 全局配置
2. 异常配置
3. 通知配置
4. 外援配置
#### 全局配置
- 全局配置有三项配置
```
prometheus:
enabled: true
project-enviroment: develop
project-name: demo
```
具体说明如下:
|名称|参数类型|说明|必要配置|
|:-:|:-:|:-:|:-:|
|enabled|boolean|用于开启项目配置,属于总控开关|是|
|project-enviroment|enum|工程环境(enum),默认为develop|否|
|project-name|string|一般忽略,以spring.application.name替代|否|
全局配置主要分以上三项,主要用于表明工程的名称、环境与全局开关,工程所处环境分了如下几个:
- dev:开发环境
- test:测试环境
- pre:预部署环境
- release:正式环境
- roll_back:回滚环境
以上5种环境基本够用。
- 异常配置分为两块,分别为异常通知配置与通知频率策略配置,具体如下配置(yml)
```
prometheus:
exceptionnotice:
enabled: true
included-trace-package: com.havefun
enable-async: true
exclude-exceptions:
- com.havefun.exceptions.TestException
include-header-name:
- tenant-id
listen-type: web
strategy:
enabled: true
frequency-type: showcount
notice-show-count: 100
# notice-time-interval: 2h
```
|名称|参数类型|说明|必要配置|
|:-:|:-:|:-:|:-:|
|enabled|boolean|基本不用,默认为true,用于开启异常通知配置|否|
|included-trace-package|string|异常追踪的包路径,一般情况下,此配置项就是配置你工程的包路径就可以了|是|
|listen-type|enum|监听类型,有两种:**common/web**,默认为common|是|
|enable-async|boolean|是否开启异步通知,默认为false|否|
|exclude-exceptions|list|排除异常,表示若出现这些异常不需要进行异常通知|否|
|include-header-name|list|异常通知中需要包含的header信息(不写全部返回)|否|
|策略配置|
|enabled|boolean|是否开启通知策略(默认否)|否|
|frequency-type|enum|通知频率策略类型:showcount/timeout|是|
|notice-show-count|int|当策略类型为showcount时,表示距上次通知再出钱多少次需要再次通知|否|
|notice-time-interval|duration|当策略类型为timeout是,表示距上次通知经过多长时间后再次通知|否|
- 以上通知中**最重要**的当属``exceptionnotice.listen-type``,此配置表示工程的监听方式,目前有两种监听方式:**普通监听(common)** ;**web监听(web)** 。这两种监听方式各有千秋,普通监听方式主要运用aop的方式对有注解的方法或类进行监听,可以加在任何类与方法上。**web监听只能对controller层进行监听,对其它层无效**,不过异常通知的信息更丰富,不仅仅包括了普通监听的所有信息(不包含参数),还包含了请求中的路径信息(path)、参数信息(param)、请求中的请求体信息(body)和请求体中的头信息(header)。例如:
```
@RestController
@RequestMapping("/demo")
public class DemoController {
@Autowired
private DingdingNoticeService dingdingNoticeService;
@Autowired
private CustomService customService;
@PostMapping("/dingding1/{pathParam}")
@ExceptionListener
public String dingding1(@PathVariable @ApiParam(value = "来个路径参数", required = true) String pathParam,
@RequestParam @ApiParam(value = "来个参数", required = true) String param,
@RequestHeader @ApiParam(value = "来个请求头", required = true) String headParam,
@RequestBody @ApiParam(value = "来个请求体", required = true) String body) {
dingdingNoticeService.dinding1();
return "Keep on going never give up.";
}
...more code
```
具体效果如下:

- 实际上钉钉机器人提供了很多其他的消息类型,这里适配了**钉钉的markdown**文本输出,只需要配置``exceptionnotice.dingding-text-type=markdown``即可,最终你可以得到以下面类似的效果:

- 项目中的异常一般分类两大类:第一类为未捕获异常,第二类为业务异常。业务异常一般由用户自己定义的异常,在javaweb项目中,假如用户的请求不满足返回结果的条件,一般是需要主动抛出自定义异常的,所以这类异常并不需要进行通知。排除不需要异常通知的配置如下:
```
prometheus.exceptionnotice.exclude-exceptions=java.lang.IllegalArgumentException,com.yourpackage.YourLogicException
```
- 上一版本的异常通知由于是同步的,由于各种各样的原因,在异常通知失败时,框架本身可能也会产生一些异常,所以增加了异步通知,主要配置为``exceptionnotice.enable-async=true``,开启异常配置需要自行配置一个线程池
一般而言,一个方法出现异常信息,意味着每当同样的方式进行调用时都会抛出相同的异常方法,放任不管的话,钉钉异常通知与邮件异常通知会重复的收到同一个异常,所以为了限制发送频率,默认情况下,某个方法出现的异常需要通知,那么这条通知**每天只会出现一次**。当然这样也可能会出现问题,假如邮件或钉钉信息没有收到,很可能会漏掉此通知,所以这里创造了一个通知的策略。
- 通知策略对应的配置类为``ExceptionNoticeFrequencyStrategy``,开启策略需要在``application.properties``中加入如下配置
```
exceptionnotice.strategy.enabled=true
```
- 目前一共有两种通知策略
- 时间策略
- 出现频次策略
对应的配置为:
```
exceptionnotice.strategy.frequency-type=timeout/showcount
```
- 时间策略对应的配置项为``exceptionnotice.strategy.notice-time-interval``,类型为duration,表示的是自上次通知时间起,超过了此配置的时间后,便会再次通知。
- 频次策略对应的配置项为``exceptionnotice.strategy.notice-show-count``,表示的是自上次通知起,出现次数超过了此配置测次数后,便会再次通知
基本上以上策略足够使用,假如说还有更好的配置策略可以连系我
#### 通知配置
- 通知配置一共三总类型:
1. 钉钉通知
2. 邮件通知
3. 自定义通知
- 钉钉通知配置:
```
prometheus:
dingding:
enabled: true
phone-num:
- 钉钉通知人的手机号
access-token: 钉钉机器人的手机号
sign-secret: 钉钉机器人秘钥
enable-signature-check: true
dingding-text-type: markdown
```
|名称|参数类型|说明|必要配置|
|:-:|:-:|:-:|:-:|
|enabled|boolean|开启钉钉通知,默认为否|是|
|phone-num|list|通知人的手机号(可以多个)|是|
|access-token|string|钉钉机器人需要的accesstoken|是|
|enable-signature-check|boolean|是否开始验签验证|否|
|sign-secret|string|验签秘钥,开启验签验证后必填|否|
|dingding-text-type|enum|钉钉通知的文本类型:text/markdown,默认为text|否|
开启签名验证时,需要在钉钉机器人的安全设置中选中*加签*设置:

- 邮件通知同样也延续了原来的邮件配置,同样依赖``spring-boot-starter-mail``及其配置
```
spring:
mail:
host: smtp.xxx.com
port: 25
username: 开启smtp权限的邮箱用户名
password: 密码
prometheus:
email:
enabled: true
email-text-type: text
to:
- 发给谁
bcc:
- 秘密抄送给谁
cc:
- 抄送给谁
```
- 框架内保留了通知所需的所有的接口,使用者可以自行定义自己的通知方式,详情请先往下看,后面有介绍
#### 外援配置
- 有邮件通知的话需要在``pom.xml``中加入如下依赖
```
org.springframework.boot
spring-boot-starter-mail
```
加入依赖后开始配置邮件信息
```
spring:
mail:
host: smtp.xxx.com
port: 25
username: 开启smtp权限的邮箱用户名
password: 密码
```
- 开启web模式的话,不说也知道,一定会引入如下依赖:
```
org.springframework.boot
spring-boot-starter-web
```
### 注解
- 上面讲的配置实际上是为此注解服务的,框架内唯一的注解``@ExceptionListener``,需要注意的是,凡是你需要异常通知的类或方法上必须加此注解。
- 根据配置类型``exceptionnotice.listen-type``的不同配置注解的位置也是不一样的
- ``exceptionnotice.listen-type=common``时``@ExceptionListener``可以加到**任意类上,任意方法上**
- ``exceptionnotice.listen-type=web``时,``@ExceptionListener``只能加在Controller层即带有``@Controller``或``@RestController``的类或者方法上,方法上也需要有对应的``@RequestMapping``相关的注解
### 自定义Config
- 目前在上面所有的配置的基础上,本框架还加入了更多的扩展配置,主要包含以下几个模块:
1. 自定义的消息通知组件
2. 自定义的异常通知文本结构
3. 自定义的http组件
- 自定义消息组件主要由函数式接口``INoticeSendComponent``进行消息发送:
```
@FunctionalInterface
public interface INoticeSendComponent {
public void send(T notice);
}
```
``INoticeSendComponent``是通知的基础接口,钉钉通知``DingDingNoticeSendComponent``与邮件通知``EmailNoticeSendComponent``都继承于此接口。其中``PromethuesNotice``是基础通知信息,目前框架内定义的子类有两个:
- ``ExceptionNotice``代表着异常通知信息的基础结构
- ``ServiceCheckNotice``代表着微服务检查通知的基础结构
配置好以后需要加入到现有的配置体系中,所以需要增加一个spring的config配置并实现``ExceptionSendComponentConfigure``接口:
```
@Configuration
public class CustomSendComponentConfig implements ExceptionSendComponentConfigure {
@Autowired
private MySendExceptionComponent mySendExceptionComponent;
@Override
public void addSendComponent(ExceptionHandler exceptionHandler) {
exceptionHandler.registerNoticeSendComponent(mySendExceptionComponent);
}
}
```
这样,自定义的消息通知系统就可以通过``@ExceptionListener``注解来使用了
```
@PutMapping("/custom")
@ExceptionListener("Tom")
public String custom() {
customService.custom();
return "Whatever is worth doing is worth doing well.";
}
//2020-01-03 20:30:46.480 ERROR 1576 --- [ometheus-task-1] c.h.components.MySendExceptionComponent : Tom-->[java.lang.NullPointerException:自定义通知第一个]
```
## 微服务监控通知
### 前言
因为我目前用的是社区版的consul注册中心,所以对于微服务的治理consul还可以过得去,问题在于加入说微服务在运行的过程中出现致命错误(堆栈溢出、服务中断等)或者连接的组件(数据库、mq等)出现问题时,作为我来说很难感知到。当然,微服务治理做的比较好的是需要花钱的(例如阿里云的EDAS)。因为有钉钉或者其他通知的接口,所以把微服务治理中服务的异常通知这一块就放在了这个工程中,同时把目前现有的功能组件化。这样也大大提高了各个组件间的协调能力。
### 咋做的

一般而言微服务的治理往往需要另外一个微服务来进行处理,这个微服务主要是进行对注册中心中微服务进行手动的相关操作的(例如重启、注销等),所以,微服务监控通知也要在此微服务中导入。启动此服务的第一步会执行一个初始化的过程,先发现现有微服务中心中所有的微服务,结合配置信息,找出三类微服务相关的异常
1. 服务缺失
2. 服务实例数量不够
3. 服务健康检查不通过
将以上三类异常服务信息进行搜集并利用``ServiceNoticeRepository``进行存储。存储下来的异常信息,将通过``ServiceNoticeTask``通知到对应的通知组件上。
### 配置
```
prometheus:
enabled: true
project-enviroment: develop
dingding:
enabled: true
phone-num: 15129072758
access-token:
sign-secret:
enable-signature-check: true
service-monitor:
auto-discovery: true
enabled: true
service-check-notice-interval: 3m
service-exist-check-interval: 3m
monitor-services:
have-fun:
service-count: 3
health-check-url: /actuator/health
health-check-headers:
test:
- aaa
check-interval: 2m
enabled: true
```
以上就是全部的异常通知配置,通知相关配置在上文有讲过,这里说一下``service-monitor``的相关配置:
|名称|参数类型|说明|必要配置|
|:-:|:-:|:-:|:-:|
|enabled|boolean|开启服务监控,默认为否|是|
|auto-discovery|boolean|是否开启自动发现服务,默认为true|否|
|service-check-notice-interval|duration|服务通知的时间间隔,默认是3分钟|否|
|service-exist-check-interval|duration|微服务存在性检查时间间隔,默认为3分钟|否|
|monitor-services|map|监控服务,key为微服务名称,value为``ServiceCheck``的配置信息|否|
|ServiceCheck|
|service-count|number|服务数量,默认为1|否|
|health-check-url|string|健康检查地址,默认为``actuator``的健康检查地址|否|
|health-check-headers|map|健康检查的header信息|否|
|check-interval|duration|健康检查的时间间隔,默认为两分钟|否|
以上就是服务监控的所有配置
## TODO 还没写完,微服务监控后面再写
[](https://gitee.com/ITEater/prometheus-spring-boot-starter)