使用回调方式(Webhook)发送告警消息

虽然夜莺已经内置了多种通知方式,但是有些用户可能有自己的通知系统,或者有些用户希望把告警消息推送到第三方系统,这时候就需要使用回调方式(Webhook)发送告警消息。

Webhook 就是一个 HTTP API 地址,夜莺产生告警事件之后,就会通过 POST 方式调用这个 API,把告警事件详情放到 HTTP Request Body 中,如此便实现了监控系统与第三方系统之间的联动。

比如电话通道,不同的公司可能使用不同的通知方式,你们公司的电话通知接口和其他公司的电话通知接口可能是不同的,夜莺无法兼容如此多的通知方式。此时,你就可以自己搞一个 HTTP Server 提供一个 API 配置到夜莺 Webhook 中,这样夜莺产生告警事件之后就会调用你的 API,你就可以在自己的 API 中拿到告警事件详情,然后调用自己公司的电话通知接口。

OK,原理如上。此时你可能会有疑问,夜莺把告警事件的详情放到 HTTP Request Body 中推给我,那这个格式具体是什么样的呢?实际上,这个数据结构就是 alert_cur_event 这个结构体的 JSON 序列化结果。

还是弄不懂?没关系,我们来看一个实际的例子。

夜莺V7版本,菜单入口:告警通知 - 通知设置 - 回调地址,页面上方其实已经给了一个说明,内容如下:

回调机制,用于夜莺和其他系统之间的集成。夜莺产生告警事件之后,会推送给各个回调地址,您可以自己开发一个 HTTP API 配置到这里,接收夜莺告警事件,进而做一些自动化的、定制化的逻辑。夜莺回调时使用的 HTTP 方法是 POST,会把告警事件的内容以 JSON 格式放到 HTTP Request Body 中,事件数据结构请参考这里。您可以找一台和夜莺网络互通的机器(假设其 IP 是 10.1.2.3),在上面用 nc 起一个端口,比如 nc -k -l 4321 即可用 nc 监听在 4321 端口,然后您把 http://10.1.2.3:4321 配置到回调地址里,然后去创建个告警规则,一旦触发,夜莺就会回调这个地址,您就可以在 nc 命令的输出中看到夜莺回调过来的详细数据格式了。

现在我在自己的环境里做个测试演示。首先找一台和夜莺网络互通的机器,其 IP 是:10.211.55.3,然后在上面用 nc 起一个端口,比如 nc -k -l 4321 如下:

  1. root@ubuntu-linux-22-04-desktop:~/tmp# nc -k -l 4321

然后我把 http://10.211.55.3:4321 配置到回调地址里,回调地址有两个地方可以配置,一个是全局的,在 告警通知 - 通知设置 - 回调地址,所有告警事件产生之后都会调用这里的回调地址。另一个是在告警规则里,是规则颗粒度的,只有这个规则产生的告警事件才会调用这个回调地址。我这里姑且配置到规则里,创建一个告警规则,回调地址配置如下:

20240227100434

稍等片刻,就可以在 nc 命令的输出中看到夜莺回调过来的详细数据格式了:

20240227100735

我这个告警规则生成了两条告警事件,所以触发了两次回调,我把其中一次回调的 JSON 拿出来,如下:

  1. {
  2. "id": 16,
  3. "cate": "prometheus",
  4. "cluster": "xxx",
  5. "datasource_id": 1,
  6. "group_id": 1,
  7. "group_name": "Default Busi Group",
  8. "hash": "0188b06deaa5eb24832548d599090f2b",
  9. "rule_id": 4,
  10. "rule_name": "测试回调地址",
  11. "rule_note": "",
  12. "rule_prod": "metric",
  13. "rule_algo": "",
  14. "severity": 2,
  15. "prom_for_duration": 0,
  16. "prom_ql": "system_load_norm_5 \u003e 0",
  17. "rule_config": {
  18. "queries": [
  19. {
  20. "keys": {
  21. "labelKey": "",
  22. "valueKey": ""
  23. },
  24. "prom_ql": "system_load_norm_5 \u003e 0",
  25. "severity": 2
  26. }
  27. ]
  28. },
  29. "prom_eval_interval": 15,
  30. "callbacks": [
  31. "http://10.211.55.3:4321"
  32. ],
  33. "runbook_url": "",
  34. "notify_recovered": 1,
  35. "notify_channels": [
  36. "email"
  37. ],
  38. "notify_groups": [
  39. "2"
  40. ],
  41. "notify_groups_obj": [
  42. {
  43. "id": 2,
  44. "name": "测试邮件告警的团队",
  45. "note": "",
  46. "create_at": 1708921626,
  47. "create_by": "root",
  48. "update_at": 1708948109,
  49. "update_by": "root"
  50. }
  51. ],
  52. "target_ident": "ulric-flashcat.local",
  53. "target_note": "",
  54. "trigger_time": 1708999492,
  55. "trigger_value": "0.7229",
  56. "trigger_values": "",
  57. "tags": [
  58. "__name__=system_load_norm_5",
  59. "ident=ulric-flashcat.local",
  60. "rulename=测试回调地址"
  61. ],
  62. "tags_map": {
  63. "__name__": "system_load_norm_5",
  64. "ident": "ulric-flashcat.local",
  65. "rulename": "测试回调地址"
  66. },
  67. "annotations": {
  68. },
  69. "is_recovered": false,
  70. "notify_users_obj": [
  71. {
  72. "id": 3,
  73. "username": "n9e-wecom-robot",
  74. "nickname": "夜莺V7群机器人",
  75. "phone": "",
  76. "email": "",
  77. "portrait": "",
  78. "roles": [
  79. "Guest"
  80. ],
  81. "contacts": {
  82. "wecom_robot_token": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=x"
  83. },
  84. "maintainer": 0,
  85. "create_at": 1708945529,
  86. "create_by": "root",
  87. "update_at": 1708945529,
  88. "update_by": "root",
  89. "admin": false
  90. },
  91. {
  92. "id": 4,
  93. "username": "n9e-ding-robot",
  94. "nickname": "钉钉机器人",
  95. "phone": "",
  96. "email": "",
  97. "portrait": "",
  98. "roles": [
  99. "Guest"
  100. ],
  101. "contacts": {
  102. "dingtalk_robot_token": "https://oapi.dingtalk.com/robot/send?access_token=x"
  103. },
  104. "maintainer": 0,
  105. "create_at": 1708948099,
  106. "create_by": "root",
  107. "update_at": 1708948099,
  108. "update_by": "root",
  109. "admin": false
  110. },
  111. {
  112. "id": 1,
  113. "username": "root",
  114. "nickname": "超管",
  115. "phone": "",
  116. "email": "",
  117. "portrait": "",
  118. "roles": [
  119. "Admin"
  120. ],
  121. "contacts": {
  122. },
  123. "maintainer": 0,
  124. "create_at": 1708920315,
  125. "create_by": "system",
  126. "update_at": 1708920315,
  127. "update_by": "system",
  128. "admin": true
  129. },
  130. {
  131. "id": 2,
  132. "username": "qinxiaohui",
  133. "nickname": "秦晓辉",
  134. "phone": "",
  135. "email": "qinxiaohui@flashcat.cloud",
  136. "portrait": "",
  137. "roles": [
  138. "Standard"
  139. ],
  140. "contacts": {
  141. },
  142. "maintainer": 0,
  143. "create_at": 1708921503,
  144. "create_by": "root",
  145. "update_at": 1708921503,
  146. "update_by": "root",
  147. "admin": false
  148. }
  149. ],
  150. "last_eval_time": 1708999492,
  151. "last_sent_time": 1708999492,
  152. "notify_cur_number": 1,
  153. "first_trigger_time": 1708999492,
  154. "extra_config": null,
  155. "status": 0,
  156. "claimant": "",
  157. "sub_rule_id": 0,
  158. "extra_info": null
  159. }

大家可以对照 alert_cur_event 这个结构体来查看,这个 JSON 就是这个结构体的 JSON 序列化结果。

之后,你就可以在自己的 API 中做一些自动化的、定制化的逻辑了。想怎么定制通知内容就怎么定制,想调用内部什么通知接口就调用什么通知接口。