# feishu-alert-robot-starter
**Repository Path**: lazygod/feishu-alert-robot-starter
## Basic Information
- **Project Name**: feishu-alert-robot-starter
- **Description**: 微服务稳定性建设组件:SpringBoot集成飞书机器人error日志、异常、汇报等消息告警
- **Primary Language**: Java
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 5
- **Created**: 2022-10-17
- **Last Updated**: 2022-10-17
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 告警机器人接入指南
### 一、介绍
**springboot服务稳定性建设基础组件starter,集成飞书机器人监控error日志、异常、汇报等发送消息告警。**(tips:可自主扩展实现企业微信、钉钉机器人告警)
**告警功能:**
1、支持即时告警文本消息
2、支持聚集告警文本消息(等待时间1min或累计消息次数达到100条的动态配置条件)
3、支持log.error(String pattern,Object... args)日志输出监控,聚集告警error日志消息
4、支持可配置全局抛出某类异常,聚集告警消息提示
**告警方式:**
1、支持配置告警消息发送群中(默认)。
2、支持配置告警消息发送群中,并且@服务负责人。
3、支持配置告警消息私发服务相应负责人。
### 二、使用场景
#### 三方调用异常告警
外部开发平台接口、上下游接口关键链路调用等,将异常告警到群进行排查修复
#### 定时任务执行结果的汇报
每次定时任务执行完成,做出一个汇报,譬如:总数量、成功数量、异常数量等
#### 代码关键流程error日志bug告警
监控代码error日志、抛出异常等发出告警消息,及时排查问题
### 三、简单接入示例
#### 群组添加自定义机器人
**第一步:添加该机器人进群。** 进入群组,打开会话设置,找到群机器人,并点击添加机器人。选择添加自定义器人加入群组。机器人添加到群组后,群内成员即可在群组中使用该机器人的功能。机器人输入一个合适的名字和描述,然后点击 下一步。

**第二步:获取webhook地址里面的robotId。** 你会获取该机器人的 webhook 地址,格式如下:https://open.feishu.cn/open-apis/bot/v2/hook/16ed2e24xxxxxxxxx(robotId)

#### 配置接入
**添加项目依赖**
````
cn.open.feishu
feishu-alert-robot-starter
1.0.0.RELEASE
````
**配置机器人参数**
配置方式一:
````
#虚拟机/环境变量服务配置
app.id = open.feishu.alert.api
env = dev
#机器人配置(默认:自定义机器人)
feishu.alert.robot.config = {"robotName":"rotbotId"}
````
配置方式二:
```
*******【properties文件配置】*******
#虚拟机/环境变量服务配置
app.id = open.feishu.alert.api
env = dev
#机器人配置(加载应用机器人与自定义机器人)
feishu.alert.app.id = cli_a11dbbb0e53a500c
feishu.alert.app.secret = xxxxxxxxxxxx
feishu.alert.robot.config = {"robot":"xxxxxxxxxxxx"}
#机器人配置(@项目负责人)
feishu.alert.mode = at_owner
feishu.alert.owner.emails = 13250113108
#跳转按钮参数配置
alert.log.kibana.enable = true
alert.log.url=https://kibana.xxxx.work/app/kibana#/discover
alert.log.stype=container
alert.monitor.enable = true
alert.monitor.url=https://monitor.xxxxx.work
*******【yaml文件配置】*******
app:
id: bfe-open-alert-api
env: dev
feishu:
alert:
app:
id: cli_a11dbbb0e53a500c
secret: xxxxxxxxxxxxxxxxxxxxxxxx
mode: at_owner
robot:
config: "{robotName:\"dabfd2a0-cdaa-496c-a98f-a19a6bef4a9e\"}"
owner:
mobiles: 13250113108,13250113109
alert:
log:
kibana:
enable: true
stype: container
url: https://kibana.xxxx.work/app/kibana#/discover
monitor:
enable: true
url: https://monitor.xxxxx.work
```
**使用示例**
````
package cn.open.feishu.alert;
import cn.open.feishu.alert.common.model.FeishuAlertRequest;
import cn.open.feishu.alert.config.FeiShuAlertAutoConfiguration;
import cn.open.feishu.alert.log.LoggerProxy;
import cn.open.feishu.alert.support.FeishuAlertService;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @Description 测试样例
* @Author fandy.lin
* @Date 2021/11/12 9:55 上午
**/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {FeiShuAlertAutoConfiguration.class})
@TestPropertySource("classpath:test.properties")
@Slf4j
public class ExampleApplicationTest {
@Autowired
FeishuAlertService feishuAlertService;
/**
* feishuAlertService.send()即时发送每一条告警消息
* @throws InterruptedException
*/
@Test
public void normalTest() throws InterruptedException {
feishuAlertService.send(new RuntimeException("异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发异常返回发呆发呆发呆发呆发"));
feishuAlertService.send("支付异常", new RuntimeException("异常返回"));
feishuAlertService.send("robot","支付异常",new RuntimeException("异常返回"));
feishuAlertService.send("robot","支付异常", new RuntimeException("异常返回"));
Thread.sleep(1000*3600);
}
/**
* feishuAlertService.sendAwait()首次或间隔60s或累计告警数量达到100,发送告警消息
* @throws InterruptedException
*/
@Test
public void concurrentTest() throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(16);
for (int i = 0; i < 1000000; i++) {
executorService.submit(() -> feishuAlertService.sendAwait(new RuntimeException("异常返回")));
executorService.submit(() -> feishuAlertService.sendAwait("支付异常", new RuntimeException("异常返回")));
}
Thread.sleep(1000*3600);
}
/**
* error级别日志打印触发机器人告警(sendAwait方式)
* @throws InterruptedException
*/
@Test
public void logTest() throws InterruptedException {
Logger log = LoggerProxy.getLogger(ExampleApplicationTest.class);
ExecutorService executorService = Executors.newFixedThreadPool(16);
for (int i = 0; i < 11; i++) {
log.error("程序error:params={}", FeishuAlertRequest.builder().msg_type("text").build());
log.error("程序发生error了:{},{}","好多","好多");
log.error("程序error:{},{},还有{}个大bug", "好多", "好多", 999.999);
log.error("程序error:{},{}", "好多", "好多", "还有一个", new RuntimeException("大bug"));
}
Thread.sleep(1000*3600);
}
}
````
**触发效果(默认)**

**触发效果(@项目负责人且按钮链接跳转)**

**触发效果(私发服务负责人)**

### 四、动态配置参数介绍
**机器人配置:**
| 配置参数 |示例 | 备注 |
| ------ | ----- | -----|
| feishu.alert.send.host | 默认:https://open.feishu.cn/open-apis/bot/v2/hook/ | 飞书机器人地址
(运行时动态生效) |
| feishu.alert.app.id | 默认:null | 配置应用机器人appId
(运行时动态生效) |
| feishu.alert.app.secret | 默认:null| 配置应用机器人appSecret
(运行时动态生效)|
| feishu.alert.mode| 默认:default| 飞书告警模式:默认发群:default,发群且@负责人:at_owner,私发负责人:send_owner
at_owner,send_owner需要配置申请飞书企业应用机器人配置好参数
(feishu.alert.app.id,feishu.alert.app.secret)
(运行时动态生效) |
| feishu.alert.owner.emails | 默认:null | 当feishu.alert.mode=at_owner,配置项目负责人emails,如:
"1@qq.com,2@qq.com"(运行时动态生效) |
| feishu.alert.await.mobiles | 默认:null | 当feishu.alert.mode=at_owner,配置项目负责人手机,如:
"13250113108,13250113107"(运行时动态生效) |
| feishu.alert.await.seconds | 默认:60 | 同一alertText飞书告警间隔时间 单位:秒
tips:避免密集告警刷屏 (运行时动态生效) |
| feishu.alert.is.enable | 默认:true | 告警机器人开关
(运行时动态生效)|
|feishu.alert.async.execute.switch|默认:true|异步发送飞书告警消息开关
(运行时动态生效)|
|feishu.alert.async.executor.core.size|默认:cpu数量|异步飞书消息告警核心线程数
(重启生效)|
|feishu.alert.async.executor.max.size |默认: cpu数量*2|异步飞书消息告警最大线程数
(重启生效)|
|feishu.alert.type.cache.init.size|默认:100|alertText计数初始缓存数量
(重启生效)|
|feishu.alert.type.cache.max.size|默认:1000|alertText计数最大缓存数量
(重启生效)|
|feishu.alert.count.limit|默认:100|同一alertText累计异常次数达到限制数,发送告警
(运行时动态生效)|
|feishu.alert.robot.config|{"xiaoai":"xxxxxxx",
"xiaobing":"xxxxxxxx"}|手动配置,可配置多个机器人发送至不同的群:
key为自定义robotName
value为webhook地址里面的robotId
(运行时动态生效)|
**跳转按钮链接配置:**
| 配置参数 |示例 | 备注 |
| ------ | ----- | -----|
| alert.kibana.log.enable | 默认:false | error日志告警消息添加kibana按钮
(运行时动态生效)|
| alert.log.url | 默认:null | kibana地址
(运行时动态生效) |
| alert.log.stype| 默认:null | kibana日志环境
(运行时动态生效) |
| alert.monitor.enable | 默认:false | 告警消息添加monitor监控按钮
(运行时动态生效) |
| alert.monitor.url | 默认:null | monitor大盘监控地址
(运行时动态生效) |
### 五、包结构介绍
````
-src.main.java.cn.open.feishu.alert
-common(公共包)
-annotation(注解类)
-model(实体类型)
-utils(工具包)
-config(配置信息)
-context(上下文环境)
-log(error日志监控实现类)
-support(告警逻辑处理类)
-src.test.java.cn.open.feishu.alert(测试示例)
-src.test.java.resources(测试参数配置)
````
### 六、FQA
**Q1:是否会出现告警失败的情况?**
高频率触发不保证一定所有告警成功,每秒20qps,大概成功触发告警数量14~16。
**Q2:关键流程异常告警、定时批处理汇报告警接入哪种方法合适?**
关键流程bug告警:建议接入sendAwait做聚合告警;定时批处理汇报告警:建议接入send做即时告警。
**Q3:飞书直接接入地址?**
https://www.feishu.cn/hc/zh-CN/articles/360024984973
**Q4:如果需要告警消息@服务负责人或发送私人能力,则需飞书开放平台申请企业自建应用机器人**
https://open.feishu.cn/document/ukTMukTMukTM/ukDNz4SO0MjL5QzM/g#top_anchor
**Q5:需要告警消息@服务负责人或私发,feishu.alert.app.id,feishu.alert.app.secret分别哪里获取?**

**Q6:申请完的应用机器人,它需要哪些权限才可以访问用户信息、私聊/群聊发送消息,即有@服务负责人能力?**

