Grafana 系列文章,版本:OOS v9.3.1
前言
我们已经知道Grafana 已经支持了钉钉、邮件等告警,钉钉能够打入Grafana 跟阿里重视开源也有关系,在Grafana的GitHub上,很早也有人提过这样的PR。
他们希望Grafana能够集成飞书,但被Grafana团队拒绝了,原因是:当时飞书通知的需求不够强烈。
不过没事,没有原生集成,我们还可以使用万能的webHook,通过中转服务内部转换参数后再发送到飞书。
创建告警规则
为了测试,数据源使用Grafana 的Test DB,新创建一个规则。
从Random Walk 类型的图表中查询数据,当数据最大值大于10的时候,发生告警,每1分钟评估一次,如果持续2分钟都符合告警条件,将生成一条告警。
这里表示告警关联的大屏和图表面板,还有一个描述字段
配置WebHook通知
这里为了测试,只填写一个接收地址,没有鉴权,外网环境必须要加鉴权
另外由于Grafana 使用Docker 部署,中转服务部署在本地物理机,如果填127.0.0.1,Docker 内部是无法访问到的,需要填物理机的局域网IP
。
配置告警策略
最后需要配置一个告警的策略,这边为了测试,时间都配的比较短,Mute timings 是不告警时间配置,可以不设。
部署中转服务
如下这段是中转服务接收到的webHook告警内容。
{
"receiver": "feishu",
"status": "resolved",
"alerts": [{
"status": "resolved",
"labels": {
"alertname": "Simple dummy streaming example",
"grafana_folder": "test"
},
"annotations": {
"description": "测试大屏告警"
},
"startsAt": "2023-01-12T14:46:00Z",
"endsAt": "2023-01-12T15:07:00Z",
"generatorURL": "http://localhost:3000/alerting/grafana/zgbSUF24z/view?orgId=1",
"fingerprint": "09b095c0ac5a31bc",
"silenceURL": "http://localhost:3000/alerting/silence/new?alertmanager=grafana\u0026matcher=alertname%3DSimple+dummy+streaming+example\u0026matcher=grafana_folder%3Dtest",
"dashboardURL": "http://localhost:3000/d/TXSTREZ?orgId=1",
"panelURL": "http://localhost:3000/d/TXSTREZ?orgId=1\u0026viewPanel=2",
"values": null,
"valueString": ""
}],
"groupLabels": {
"alertname": "Simple dummy streaming example"
},
"commonLabels": {
"alertname": "Simple dummy streaming example",
"grafana_folder": "test"
},
"commonAnnotations": {
"description": "测试大屏告警"
},
"externalURL": "http://localhost:3000/",
"version": "1",
"groupKey": "{}/{}:{alertname=\"Simple dummy streaming example\"}",
"truncatedAlerts": 0,
"orgId": 1,
"title": "[RESOLVED] Simple dummy streaming example (test)",
"state": "ok",
"message": "**Resolved**\n\nValue: [no value]\nLabels:\n - alertname = Simple dummy streaming example\n - grafana_folder = test\nAnnotations:\n - description = 测试大屏告警\nSource: http://localhost:3000/alerting/grafana/zgbSUF24z/view?orgId=1\nSilence: http://localhost:3000/alerting/silence/new?alertmanager=grafana\u0026matcher=alertname%3DSimple+dummy+streaming+example\u0026matcher=grafana_folder%3Dtest\nDashboard: http://localhost:3000/d/TXSTREZ?orgId=1\nPanel: http://localhost:3000/d/TXSTREZ?orgId=1\u0026viewPanel=2\n"
}
上面的字段也很好理解,我们将上面的字段解析封装成飞书的通知格式就可以往飞书发送通知了。
我们根据之前的代码,简单调整封装一下。
AlarmMessage.java 告警接口
public interface AlarmMessage {
/**
* 发送文本告警
* @param content
*/
void sendData(String content);
}
FeiShuNotifier.java 飞书发送告警代码
@Service
public class FeiShuNotifier implements AlarmMessage {
private static final String DEFAULT_MESSAGE = " 告警标题:#{title} \n 告警描述:#{description} \n 面板URL:#{panelUrl} \n 发生时间:#{startTime}";
private final SpelExpressionParser parser = new SpelExpressionParser();
@Value("${feishu.webhook-url}")
private String webhookUrl;
@Value("${feishu.secret}")
private String secret;
private Expression message = parser.parseExpression(DEFAULT_MESSAGE, ParserContext.TEMPLATE_EXPRESSION);
private RestTemplate restTemplate = new RestTemplate();
@Override
public void sendData(String content) {
Map<String, Object> message = createMessage(getText(content));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
restTemplate.postForEntity(webhookUrl, new HttpEntity<>(message, headers), Void.class);
}
/**
* 构建通知报文
* @param content
* @return
*/
protected Map<String, Object> createMessage(String content) {
Map<String, Object> messageJson = new HashMap<>();
messageJson.put("msg_type", "text");
Map<String, Object> text = new HashMap<>();
text.put("text", content);
messageJson.put("content", text);
Long timestamp = System.currentTimeMillis() / 1000;
messageJson.put("timestamp", timestamp);
messageJson.put("sign", getSign(timestamp));
return messageJson;
}
/**
* 构建文本内容
* @param body
* @return
*/
private String getText(String body) {
JSONObject json = JSON.parseObject(body);
Map<String, Object> root = new HashMap<>();
root.put("title", json.getString("title"));
root.put("description", json.getJSONObject("commonAnnotations").getString("description"));
JSONObject alertObject = json.getJSONArray("alerts").getJSONObject(0);
root.put("panelUrl", alertObject.getString("panelURL"));
root.put("startTime", DateUtil.parseUTC(alertObject.getString("startsAt")).toString(TimeZone.getDefault()));
StandardEvaluationContext context = new StandardEvaluationContext(root);
context.addPropertyAccessor(new MapAccessor());
return message.getValue(context, String.class);
}
private String getSign(Long timestamp) {
try {
String stringToSign = timestamp + "\n" + secret;
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(stringToSign.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
byte[] signData = mac.doFinal(new byte[]{
});
return new String(Base64.encodeBase64(signData, false));
}
catch (Exception ex) {
ex.printStackTrace();
}
return "";
}
}
webhook 接口代码
@RestController
public class WebhookController {
@Resource
private FeiShuNotifier feiShuNotifier;
@RequestMapping("/webhook/receive")
public void receive(@RequestBody String message) {
feiShuNotifier.sendData(message);
}
}
下面为飞书接收到的告警:
另外如果还需要接入企业微信等其他聊天工具,可以使用开源的
PrometheusAlert
,使用方案见其GitHub。
https://github.com/feiyu563/PrometheusAlert
作者其他文章:
- Spring Boot Admin 参考指南
- SpringBoot Admin服务离线、不显示健康信息的问题
- Spring Boot Admin2 @EnableAdminServer的加载
- Spring Boot Admin2 AdminServerAutoConfiguration详解
- Spring Boot Admin2 实例状态监控详解
- Spring Boot Admin2 自定义JVM监控通知
- Spring Boot Admin2 自定义异常监控
- Spring Boot Admin 监控指标接入Grafana可视化
Spring Security相关文章:
- OAuth2的定义和运行流程
- Spring Security OAuth实现Gitee快捷登录
- Spring Security OAuth实现GitHub快捷登录
- Spring Security的过滤器链机制
- Spring Security OAuth Client配置加载源码分析
- Spring Security内置过滤器详解
- 为什么加载了两个OAuth2AuthorizationRequestRedirectFilter分析
- Spring Security 自定义授权服务器实践
- Spring Security 自定义资源服务器实践
- Spring Security 自定义用户信息端点与多种登录方式共存
- Spring Security 之密码存储
- Spring Security 之防漏洞攻击
转载:https://blog.csdn.net/weixin_40972073/article/details/128665497