夜莺短信告警教程

巴辉特 2024-11-28 09:20:06

夜莺监控(Nightingale)已经内置支持了邮件、钉钉、飞书、企微等多种通知机制,但是没有内置支持电话、短信等方式,是因为邮件、钉钉、企微、飞书等方式是协议固定的,但是电话、短信的通知方式,各家不同,一个是短信通道供应商不同,一个是各家封装的电话、短信接口不同,所以夜莺没有内置支持。

不过好在夜莺支持通过自定义脚本的方式对接新的通知媒介,只要你会写脚本,就可以接入任何通知媒介,电话、短信自然也不在话下。本文会以短信通知为例,讲解个中原理和配置方式。

告警通知这块,不仅仅是把告警消息投递出去,还需要告警降噪、按规则分派、排班、认领、升级、和 IM 打通、统计分析等更多诉求,我们建议您使用 FlashDuty 来作为一站式告警 OnCall 响应平台,可以对接 Nightingale、Prometheus、Zabbix、各类云监控,把众多监控系统的告警集中到一个中心平台来处理,提升告警处理效率。当然,也省去了您编写脚本的麻烦。

1. 增加短信通知媒介

菜单位置:告警通知-通知设置-通知媒介。点击下面的添加,增加一个新的通知媒介,名称就叫“短信”即可,标识就叫“sms”即可,如下图所示:

增加短信通知媒介

增加通知媒介之后,在告警规则的配置页面,就可以勾选“短信”这个通知媒介了,如下图所示:

告警规则出现短信通知媒介

2. 编写短信通知模板

每一种通知媒介,都有对应的通知模板,啥意思呢?告警事件原本的格式是一条大 JSON,显然没法直接发出去,通过邮件发的时候要把这个 JSON 中的重要字段提取出来拼成 HTML 格式的邮件,发钉钉的时候要把这个 JSON 中的重要字段提取出来拼成 markdown 格式的消息,发短信的时候也是一样,要把这个 JSON 中的重要字段提取出来拼成短信的格式。

短信一般是普通文本字符串,有长度限制,咱们尽量只放重要内容,比如告警标题、告警内容、告警级别、告警时间等等,不要放太多无关紧要的信息,因为短信费用是按字数算的。

短信通知模板

菜单入口在:告警通知-通知模板,创建一个短信模板,标识姑且也叫 sms,内容就是你想要发送的短信内容,比如:

**级别状态**: {{if .IsRecovered}}S{{.Severity}} Recovered{{else}}S{{.Severity}} Triggered{{end}}   
**规则标题**: {{.RuleName}}
**监控指标**: {{.TagsJSON}}
{{- if not .IsRecovered}}   
**触发时值**: {{.TriggerValue}}
{{- end}}   
**发送时间**: {{timestamp}}

这个内容是可以自定义的,遵从 go template 语法,你可以参考其他的模板学习具体的写法。

n9e 的进程在调用通知脚本的时候,会把告警事件作为变量传给各个通知模板,进而渲染出最终的通知内容,然后把渲染结果+事件详情传给脚本,脚本中就可以直接取用了,无需再去处理模板渲染逻辑。

联系我们交流

3. 编写短信通知脚本

夜莺告警的时候,可以自动调用通知脚本,你就在通知脚本里写你的逻辑就可以了。脚本需要先启用,菜单入口:告警通知-通知设置-通知脚本,如下图:

通知脚本

我这里设置为启用,超时时间 10s,然后贴了一段脚本内容,内容如下:

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
import sys
import json

class Sender(object):
    @classmethod
    def send_email(cls, payload):
        # already done in go code
        pass

    @classmethod
    def send_wecom(cls, payload):
        # already done in go code
        pass

    @classmethod
    def send_dingtalk(cls, payload):
        # already done in go code
        pass

    @classmethod
    def send_feishu(cls, payload):
        # already done in go code
        pass

    @classmethod
    def send_mm(cls, payload):
        # already done in go code
        pass

    @classmethod
    def send_sms(cls, payload):
        users = payload.get('event').get("notify_users_obj")
        phones = {}
        for u in users:
            if u.get("phone"):
                phones[u.get("phone")] = 1
        if phones:
            print("send_sms not implemented, phones: {}".format(phones.keys()))

    @classmethod
    def send_voice(cls, payload):
        users = payload.get('event').get("notify_users_obj")
        phones = {}
        for u in users:
            if u.get("phone"):
                phones[u.get("phone")] = 1
        if phones:
            print("send_voice not implemented, phones: {}".format(phones.keys()))

def main():
    payload = json.load(sys.stdin)
    with open(".payload", 'w') as f:
        f.write(json.dumps(payload, indent=4))
    for ch in payload.get('event').get('notify_channels'):
        send_func_name = "send_{}".format(ch.strip())
        if not hasattr(Sender, send_func_name):
            print("function: {} not found", send_func_name)
            continue
        send_func = getattr(Sender, send_func_name)
        send_func(payload)

def hello():
    print("hello nightingale")

if __name__ == "__main__":
    if len(sys.argv) == 1:
        main()
    elif sys.argv[1] == "hello":
        hello()
    else:
        print("I am confused")

显然这是一段 Python 脚本,比较简单,入口是 main 函数,从 stdin 中读取内容,然后根据告警事件中的通知渠道,调用 Sender 类中对应的发送函数,比如 send_sms、send_voice 等等,这里只是打印了一下,实际上应该是调用短信供应商的接口,把短信发送出去。

我来详细解释一下:

  • payload = json.load(sys.stdin) 夜莺 n9e 进程会把告警事件 encode 成一个 json,通过 stdin 的方式传给脚本,脚本里自然就通过 sys.stdin 的方式接收,因为是 json 字符串,使用 json.load 解码成 payload 对象
  • 然后把 payload 的内容打印到 .payload 文件中,方便调试,方便我们了解夜莺进程到底发过来了个什么内容

下面我把我的环境里的 .payload 贴到下面,怎么找到 .payload 呢?去 n9e 二进制的同级目录下找,注意这是一个隐藏文件。

{
    "event": {
        "id": 1,
        "cate": "prometheus",
        "cluster": "vm01",
        "datasource_id": 1,
        "group_id": 1,
        "group_name": "Default Busi Group",
        "hash": "ac7546f009158fe945933780cd2f3ff3",
        "rule_id": 1,
        "rule_name": "test sms alerting",
        "rule_note": "",
        "rule_prod": "metric",
        "rule_algo": "",
        "severity": 2,
        "prom_for_duration": 0,
        "prom_ql": "cpu_usage_active{ident=\"mac-vm-001\"}>0",
        "rule_config": {
            "queries": [
                {
                    "prom_ql": "cpu_usage_active{ident=\"mac-vm-001\"}>0",
                    "severity": 2,
                    "unit": "none"
                }
            ]
        },
        "prom_eval_interval": 10,
        "callbacks": [],
        "runbook_url": "",
        "notify_recovered": 1,
        "notify_channels": [
            "sms"
        ],
        "notify_groups": [
            "1"
        ],
        "notify_groups_obj": [
            {
                "id": 1,
                "name": "demo-root-group",
                "note": "",
                "create_at": 1732094402,
                "create_by": "root",
                "update_at": 1732094402,
                "update_by": "root",
                "users": null
            }
        ],
        "target_ident": "mac-vm-001",
        "target_note": "",
        "trigger_time": 1732756597,
        "trigger_value": "5.03804",
        "trigger_values": "",
        "trigger_values_json": {
            "values_with_unit": {
                "v": {
                    "value": 5.038038883421,
                    "unit": "",
                    "text": "5.04",
                    "stat": 5.038038883421
                }
            }
        },
        "tags": [
            "__name__=cpu_usage_active",
            "cpu=cpu-total",
            "ident=mac-vm-001",
            "rulename=test sms alerting"
        ],
        "tags_map": {
            "__name__": "cpu_usage_active",
            "cpu": "cpu-total",
            "ident": "mac-vm-001",
            "rulename": "test sms alerting"
        },
        "original_tags": null,
        "annotations": {},
        "is_recovered": false,
        "notify_users_obj": [
            {
                "id": 1,
                "username": "root",
                "nickname": "\u8d85\u7ba1",
                "phone": "18612185520",
                "email": "",
                "portrait": "/image/avatar1.png",
                "roles": [
                    "Admin"
                ],
                "contacts": {},
                "maintainer": 0,
                "create_at": 1732094402,
                "create_by": "system",
                "update_at": 1732756566,
                "update_by": "root",
                "belong": "",
                "admin": true,
                "user_groups": null,
                "busi_groups": null,
                "last_active_time": 1732756588
            }
        ],
        "last_eval_time": 1732756597,
        "last_sent_time": 1732756597,
        "notify_cur_number": 1,
        "first_trigger_time": 1732756597,
        "extra_config": null,
        "status": 0,
        "claimant": "",
        "sub_rule_id": 0,
        "extra_info": null,
        "target": {
            "id": 2,
            "group_id": 0,
            "group_objs": null,
            "ident": "mac-vm-001",
            "note": "",
            "tags": [],
            "tags_maps": {},
            "update_at": 1732756595,
            "host_ip": "10.211.55.3",
            "agent_version": "v0.3.60",
            "engine_name": "default",
            "os": "linux",
            "host_tags": null,
            "unixtime": 1732756586936,
            "offset": 18,
            "target_up": 2,
            "mem_util": 17.314975929184705,
            "cpu_num": 4,
            "cpu_util": 4.303797466603506,
            "arch": "arm64",
            "remote_addr": "172.27.0.1",
            "group_ids": null,
            "group_names": []
        },
        "recover_config": {
            "judge_type": 0,
            "recover_exp": ""
        },
        "rule_hash": "3abc1f400d7338cae3785ecb826eac7c",
        "extra_info_map": null
    },
    "tpls": {
        "dingtalk": "#### <font color=\"#FF0000\">\ud83d\udc94test sms alerting</font>\n\n---\n\n- **\u544a\u8b66\u7ea7\u522b**: 2\u7ea7\n- **\u5f53\u6b21\u89e6\u53d1\u65f6\u503c**: 5.03804\n- **\u5f53\u6b21\u89e6\u53d1\u65f6\u95f4**: 2024-11-28 09:16:37\n- **\u544a\u8b66\u6301\u7eed\u65f6\u957f**: 0s\n- **\u544a\u8b66\u4e8b\u4ef6\u6807\u7b7e**:\n\t- __name__: cpu_usage_active\n\t- cpu: cpu-total\n\t- ident: mac-vm-001\n   \n[\u4e8b\u4ef6\u8be6\u60c5](http://\u8bf7\u8054\u7cfb\u7ba1\u7406\u5458\u4fee\u6539\u901a\u77e5\u6a21\u677f\u5c06\u57df\u540d\u66ff\u6362\u4e3a\u5b9e\u9645\u7684\u57df\u540d/alert-his-events/1)|[\u5c4f\u853d1\u5c0f\u65f6](http://\u8bf7\u8054\u7cfb\u7ba1\u7406\u5458\u4fee\u6539\u901a\u77e5\u6a21\u677f\u5c06\u57df\u540d\u66ff\u6362\u4e3a\u5b9e\u9645\u7684\u57df\u540d/alert-mutes/add?busiGroup=1&cate=prometheus&datasource_ids=1&prod=metric&tags=__name__%3Dcpu_usage_active&tags=cpu%3Dcpu-total&tags=ident%3Dmac-vm-001&tags=rulename%3Dtest sms alerting)|[\u67e5\u770b\u66f2\u7ebf](http://\u8bf7\u8054\u7cfb\u7ba1\u7406\u5458\u4fee\u6539\u901a\u77e5\u6a21\u677f\u5c06\u57df\u540d\u66ff\u6362\u4e3a\u5b9e\u9645\u7684\u57df\u540d/metric/explorer?data_source_id=1&data_source_name=prometheus&mode=graph&prom_ql=cpu_usage_active%7Bident=%22mac-vm-001%22%7D%3E0)",
        "email": "<!DOCTYPE html>\n\t<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"UTF-8\">\n\t\t<meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n\t\t<title>\u591c\u83ba\u544a\u8b66\u901a\u77e5</title>\n\t\t<style type=\"text/css\">\n\t\t\t.wrapper {\n\t\t\t\tbackground-color: #f8f8f8;\n\t\t\t\tpadding: 15px;\n\t\t\t\theight: 100%;\n\t\t\t}\n\t\t\t.main {\n\t\t\t\twidth: 600px;\n\t\t\t\tpadding: 30px;\n\t\t\t\tmargin: 0 auto;\n\t\t\t\tbackground-color: #fff;\n\t\t\t\tfont-size: 12px;\n\t\t\t\tfont-family: verdana,'Microsoft YaHei',Consolas,'Deja Vu Sans Mono','Bitstream Vera Sans Mono';\n\t\t\t}\n\t\t\theader {\n\t\t\t\tborder-radius: 2px 2px 0 0;\n\t\t\t}\n\t\t\theader .title {\n\t\t\t\tfont-size: 14px;\n\t\t\t\tcolor: #333333;\n\t\t\t\tmargin: 0;\n\t\t\t}\n\t\t\theader .sub-desc {\n\t\t\t\tcolor: #333;\n\t\t\t\tfont-size: 14px;\n\t\t\t\tmargin-top: 6px;\n\t\t\t\tmargin-bottom: 0;\n\t\t\t}\n\t\t\thr {\n\t\t\t\tmargin: 20px 0;\n\t\t\t\theight: 0;\n\t\t\t\tborder: none;\n\t\t\t\tborder-top: 1px solid #e5e5e5;\n\t\t\t}\n\t\t\tem {\n\t\t\t\tfont-weight: 600;\n\t\t\t}\n\t\t\ttable {\n\t\t\t\tmargin: 20px 0;\n\t\t\t\twidth: 100%;\n\t\t\t}\n\t\n\t\t\ttable tbody tr{\n\t\t\t\tfont-weight: 200;\n\t\t\t\tfont-size: 12px;\n\t\t\t\tcolor: #666;\n\t\t\t\theight: 32px;\n\t\t\t}\n\t\n\t\t\t.succ {\n\t\t\t\tbackground-color: green;\n\t\t\t\tcolor: #fff;\n\t\t\t}\n\t\n\t\t\t.fail {\n\t\t\t\tbackground-color: red;\n\t\t\t\tcolor: #fff;\n\t\t\t}\n\t\n\t\t\t.succ th, .succ td, .fail th, .fail td {\n\t\t\t\tcolor: #fff;\n\t\t\t}\n\t\n\t\t\ttable tbody tr th {\n\t\t\t\twidth: 80px;\n\t\t\t\ttext-align: right;\n\t\t\t}\n\t\t\t.text-right {\n\t\t\t\ttext-align: right;\n\t\t\t}\n\t\t\t.body {\n\t\t\t\tmargin-top: 24px;\n\t\t\t}\n\t\t\t.body-text {\n\t\t\t\tcolor: #666666;\n\t\t\t\t-webkit-font-smoothing: antialiased;\n\t\t\t}\n\t\t\t.body-extra {\n\t\t\t\t-webkit-font-smoothing: antialiased;\n\t\t\t}\n\t\t\t.body-extra.text-right a {\n\t\t\t\ttext-decoration: none;\n\t\t\t\tcolor: #333;\n\t\t\t}\n\t\t\t.body-extra.text-right a:hover {\n\t\t\t\tcolor: #666;\n\t\t\t}\n\t\t\t.button {\n\t\t\t\twidth: 200px;\n\t\t\t\theight: 50px;\n\t\t\t\tmargin-top: 20px;\n\t\t\t\ttext-align: center;\n\t\t\t\tborder-radius: 2px;\n\t\t\t\tbackground: #2D77EE;\n\t\t\t\tline-height: 50px;\n\t\t\t\tfont-size: 20px;\n\t\t\t\tcolor: #FFFFFF;\n\t\t\t\tcursor: pointer;\n\t\t\t}\n\t\t\t.button:hover {\n\t\t\t\tbackground: rgb(25, 115, 255);\n\t\t\t\tborder-color: rgb(25, 115, 255);\n\t\t\t\tcolor: #fff;\n\t\t\t}\n\t\t\tfooter {\n\t\t\t\tmargin-top: 10px;\n\t\t\t\ttext-align: right;\n\t\t\t}\n\t\t\t.footer-logo {\n\t\t\t\ttext-align: right;\n\t\t\t}\n\t\t\t.footer-logo-image {\n\t\t\t\twidth: 108px;\n\t\t\t\theight: 27px;\n\t\t\t\tmargin-right: 10px;\n\t\t\t}\n\t\t\t.copyright {\n\t\t\t\tmargin-top: 10px;\n\t\t\t\tfont-size: 12px;\n\t\t\t\ttext-align: right;\n\t\t\t\tcolor: #999;\n\t\t\t\t-webkit-font-smoothing: antialiased;\n\t\t\t}\n\t\t</style>\n\t</head>\n\t<body>\n\t<div class=\"wrapper\">\n\t\t<div class=\"main\">\n\t\t\t<header>\n\t\t\t\t<h3 class=\"title\">test sms alerting</h3>\n\t\t\t\t<p class=\"sub-desc\"></p>\n\t\t\t</header>\n\t\n\t\t\t<hr>\n\t\n\t\t\t<div class=\"body\">\n\t\t\t\t<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\">\n\t\t\t\t\t<tbody>\n\t\t\t\t\t\n\t\t\t\t\t<tr class=\"fail\">\n\t\t\t\t\t\t<th>\u7ea7\u522b\u72b6\u6001\uff1a</th>\n\t\t\t\t\t\t<td>S2 Triggered</td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t\n\t\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>\u7b56\u7565\u5907\u6ce8\uff1a</th>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>\u8bbe\u5907\u5907\u6ce8\uff1a</th>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>\u89e6\u53d1\u65f6\u503c\uff1a</th>\n\t\t\t\t\t\t<td>5.03804</td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t\n\t\n\t\t\t\t\t\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>\u76d1\u63a7\u5bf9\u8c61\uff1a</th>\n\t\t\t\t\t\t<td>mac-vm-001</td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>\u76d1\u63a7\u6307\u6807\uff1a</th>\n\t\t\t\t\t\t<td>[__name__=cpu_usage_active cpu=cpu-total ident=mac-vm-001 rulename=test sms alerting]</td>\n\t\t\t\t\t</tr>\n\t\n\t\t\t\t\t\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>\u89e6\u53d1\u65f6\u95f4\uff1a</th>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t2024-11-28 09:16:37\n\t\t\t\t\t\t</td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t\n\t\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>\u53d1\u9001\u65f6\u95f4\uff1a</th>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t2024-11-28 09:16:37\n\t\t\t\t\t\t</td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t</tbody>\n\t\t\t\t</table>\n\t\n\t\t\t\t<hr>\n\t\n\t\t\t\t<footer>\n\t\t\t\t\t<div class=\"copyright\" style=\"font-style: italic\">\n\t\t\t\t\t\t\u62a5\u8b66\u592a\u591a\uff1f\u4f7f\u7528 <a href=\"https://flashcat.cloud/product/flashduty/\" target=\"_blank\">FlashDuty</a> \u505a\u544a\u8b66\u805a\u5408\u964d\u566a\u3001\u6392\u73edOnCall\uff01\n\t\t\t\t\t</div>\n\t\t\t\t</footer>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n\t</body>\n\t</html>",
        "feishu": "\u7ea7\u522b\u72b6\u6001: S2 Triggered   \n\u89c4\u5219\u540d\u79f0: test sms alerting   \n\u76d1\u63a7\u6307\u6807: [__name__=cpu_usage_active cpu=cpu-total ident=mac-vm-001 rulename=test sms alerting]\n\u89e6\u53d1\u65f6\u95f4: 2024-11-28 09:16:37\n\u89e6\u53d1\u65f6\u503c: 5.03804\n\u53d1\u9001\u65f6\u95f4: 2024-11-28 09:16:37\n   \n\u4e8b\u4ef6\u8be6\u60c5: http://\u8bf7\u8054\u7cfb\u7ba1\u7406\u5458\u4fee\u6539\u901a\u77e5\u6a21\u677f\u5c06\u57df\u540d\u66ff\u6362\u4e3a\u5b9e\u9645\u7684\u57df\u540d/alert-his-events/1\n\u5c4f\u853d1\u5c0f\u65f6: http://\u8bf7\u8054\u7cfb\u7ba1\u7406\u5458\u4fee\u6539\u901a\u77e5\u6a21\u677f\u5c06\u57df\u540d\u66ff\u6362\u4e3a\u5b9e\u9645\u7684\u57df\u540d/alert-mutes/add?busiGroup=1&cate=prometheus&datasource_ids=1&prod=metric&tags=__name__%3Dcpu_usage_active&tags=cpu%3Dcpu-total&tags=ident%3Dmac-vm-001&tags=rulename%3Dtest sms alerting",
        "feishucard": "   \n**\u544a\u8b66\u96c6\u7fa4:** vm01   \n**\u7ea7\u522b\u72b6\u6001:** S2 Triggered   \n**\u544a\u8b66\u540d\u79f0:** test sms alerting   \n**\u89e6\u53d1\u65f6\u95f4:** 2024-11-28 09:16:37   \n**\u53d1\u9001\u65f6\u95f4:** 2024-11-28 09:16:37   \n**\u89e6\u53d1\u65f6\u503c:** 5.03804   \n   \n[\u4e8b\u4ef6\u8be6\u60c5](http://\u8bf7\u8054\u7cfb\u7ba1\u7406\u5458\u4fee\u6539\u901a\u77e5\u6a21\u677f\u5c06\u57df\u540d\u66ff\u6362\u4e3a\u5b9e\u9645\u7684\u57df\u540d/alert-his-events/1)|[\u5c4f\u853d1\u5c0f\u65f6](http://\u8bf7\u8054\u7cfb\u7ba1\u7406\u5458\u4fee\u6539\u901a\u77e5\u6a21\u677f\u5c06\u57df\u540d\u66ff\u6362\u4e3a\u5b9e\u9645\u7684\u57df\u540d/alert-mutes/add?busiGroup=1&cate=prometheus&datasource_ids=1&prod=metric&tags=__name__%3Dcpu_usage_active&tags=cpu%3Dcpu-total&tags=ident%3Dmac-vm-001&tags=rulename%3Dtest sms alerting)|[\u67e5\u770b\u66f2\u7ebf](http://\u8bf7\u8054\u7cfb\u7ba1\u7406\u5458\u4fee\u6539\u901a\u77e5\u6a21\u677f\u5c06\u57df\u540d\u66ff\u6362\u4e3a\u5b9e\u9645\u7684\u57df\u540d/metric/explorer?data_source_id=1&data_source_name=prometheus&mode=graph&prom_ql=cpu_usage_active%7Bident=%22mac-vm-001%22%7D%3E0)",
        "lark": "\u7ea7\u522b\u72b6\u6001: S2 Triggered   \n\u89c4\u5219\u540d\u79f0: test sms alerting   \n\u76d1\u63a7\u6307\u6807: [__name__=cpu_usage_active cpu=cpu-total ident=mac-vm-001 rulename=test sms alerting]\n\u89e6\u53d1\u65f6\u95f4: 2024-11-28 09:16:37\n\u89e6\u53d1\u65f6\u503c: 5.03804\n\u53d1\u9001\u65f6\u95f4: 2024-11-28 09:16:37\n   \n\u4e8b\u4ef6\u8be6\u60c5: http://\u8bf7\u8054\u7cfb\u7ba1\u7406\u5458\u4fee\u6539\u901a\u77e5\u6a21\u677f\u5c06\u57df\u540d\u66ff\u6362\u4e3a\u5b9e\u9645\u7684\u57df\u540d/alert-his-events/1\n\u5c4f\u853d1\u5c0f\u65f6: http://\u8bf7\u8054\u7cfb\u7ba1\u7406\u5458\u4fee\u6539\u901a\u77e5\u6a21\u677f\u5c06\u57df\u540d\u66ff\u6362\u4e3a\u5b9e\u9645\u7684\u57df\u540d/alert-mutes/add?busiGroup=1&cate=prometheus&datasource_ids=1&prod=metric&tags=__name__%3Dcpu_usage_active&tags=cpu%3Dcpu-total&tags=ident%3Dmac-vm-001&tags=rulename%3Dtest sms alerting",
        "larkcard": "   \n**\u544a\u8b66\u96c6\u7fa4:** vm01   \n**\u7ea7\u522b\u72b6\u6001:** S2 Triggered   \n**\u544a\u8b66\u540d\u79f0:** test sms alerting   \n**\u89e6\u53d1\u65f6\u95f4:** 2024-11-28 09:16:37   \n**\u53d1\u9001\u65f6\u95f4:** 2024-11-28 09:16:37   \n**\u89e6\u53d1\u65f6\u503c:** 5.03804\n**\u6301\u7eed\u65f6\u957f**: 0s   \n   \n[\u4e8b\u4ef6\u8be6\u60c5](http://\u8bf7\u8054\u7cfb\u7ba1\u7406\u5458\u4fee\u6539\u901a\u77e5\u6a21\u677f\u5c06\u57df\u540d\u66ff\u6362\u4e3a\u5b9e\u9645\u7684\u57df\u540d/alert-his-events/1)|[\u5c4f\u853d1\u5c0f\u65f6](http://\u8bf7\u8054\u7cfb\u7ba1\u7406\u5458\u4fee\u6539\u901a\u77e5\u6a21\u677f\u5c06\u57df\u540d\u66ff\u6362\u4e3a\u5b9e\u9645\u7684\u57df\u540d/alert-mutes/add?busiGroup=1&cate=prometheus&datasource_ids=1&prod=metric&tags=__name__%3Dcpu_usage_active&tags=cpu%3Dcpu-total&tags=ident%3Dmac-vm-001&tags=rulename%3Dtest sms alerting)|[\u67e5\u770b\u66f2\u7ebf](http://\u8bf7\u8054\u7cfb\u7ba1\u7406\u5458\u4fee\u6539\u901a\u77e5\u6a21\u677f\u5c06\u57df\u540d\u66ff\u6362\u4e3a\u5b9e\u9645\u7684\u57df\u540d/metric/explorer?data_source_id=1&data_source_name=prometheus&mode=graph&prom_ql=cpu_usage_active%7Bident=%22mac-vm-001%22%7D%3E0)",
        "mailsubject": "Triggered: test sms alerting [__name__=cpu_usage_active cpu=cpu-total ident=mac-vm-001 rulename=test sms alerting]",
        "mm": "\u7ea7\u522b\u72b6\u6001: S2 Triggered   \n\u89c4\u5219\u540d\u79f0: test sms alerting   \n\u76d1\u63a7\u6307\u6807: [__name__=cpu_usage_active cpu=cpu-total ident=mac-vm-001 rulename=test sms alerting]   \n\u89e6\u53d1\u65f6\u95f4: 2024-11-28 09:16:37   \n\u89e6\u53d1\u65f6\u503c: 5.03804   \n\u53d1\u9001\u65f6\u95f4: 2024-11-28 09:16:37",
        "sms": "**\u7ea7\u522b\u72b6\u6001**: S2 Triggered   \n**\u89c4\u5219\u6807\u9898**: test sms alerting\n**\u76d1\u63a7\u6307\u6807**: [__name__=cpu_usage_active cpu=cpu-total ident=mac-vm-001 rulename=test sms alerting]   \n**\u89e6\u53d1\u65f6\u503c**: 5.03804   \n**\u53d1\u9001\u65f6\u95f4**: 2024-11-28 09:16:37\n",
        "telegram": "**\u7ea7\u522b\u72b6\u6001**: <font color=\"warning\">S2 Triggered</font>   \n**\u89c4\u5219\u6807\u9898**: test sms alerting   \n**\u76d1\u63a7\u5bf9\u8c61**: mac-vm-001   \n**\u76d1\u63a7\u6307\u6807**: [__name__=cpu_usage_active cpu=cpu-total ident=mac-vm-001 rulename=test sms alerting]   \n**\u89e6\u53d1\u65f6\u503c**: 5.03804   \n**\u9996\u6b21\u89e6\u53d1\u65f6\u95f4**: 2024-11-28 09:16:37   \n**\u8ddd\u79bb\u9996\u6b21\u544a\u8b66**: 0s\n**\u53d1\u9001\u65f6\u95f4**: 2024-11-28 09:16:37",
        "wecom": "**\u7ea7\u522b\u72b6\u6001**: <font color=\"warning\">S2 Triggered</font>   \n**\u89c4\u5219\u6807\u9898**: test sms alerting   \n**\u76d1\u63a7\u5bf9\u8c61**: mac-vm-001   \n**\u76d1\u63a7\u6307\u6807**: [__name__=cpu_usage_active cpu=cpu-total ident=mac-vm-001 rulename=test sms alerting]   \n**\u89e6\u53d1\u65f6\u503c**: 5.03804   \n**\u9996\u6b21\u89e6\u53d1\u65f6\u95f4**: 2024-11-28 09:16:37   \n**\u8ddd\u79bb\u9996\u6b21\u544a\u8b66**: 0s\n**\u53d1\u9001\u65f6\u95f4**: 2024-11-28 09:16:37\n   \n[\u4e8b\u4ef6\u8be6\u60c5](http://\u8bf7\u8054\u7cfb\u7ba1\u7406\u5458\u4fee\u6539\u901a\u77e5\u6a21\u677f\u5c06\u57df\u540d\u66ff\u6362\u4e3a\u5b9e\u9645\u7684\u57df\u540d/alert-his-events/1)|[\u5c4f\u853d1\u5c0f\u65f6](http://\u8bf7\u8054\u7cfb\u7ba1\u7406\u5458\u4fee\u6539\u901a\u77e5\u6a21\u677f\u5c06\u57df\u540d\u66ff\u6362\u4e3a\u5b9e\u9645\u7684\u57df\u540d/alert-mutes/add?busiGroup=1&cate=prometheus&datasource_ids=1&prod=metric&tags=__name__%3Dcpu_usage_active&tags=cpu%3Dcpu-total&tags=ident%3Dmac-vm-001&tags=rulename%3Dtest sms alerting)|[\u67e5\u770b\u66f2\u7ebf](http://\u8bf7\u8054\u7cfb\u7ba1\u7406\u5458\u4fee\u6539\u901a\u77e5\u6a21\u677f\u5c06\u57df\u540d\u66ff\u6362\u4e3a\u5b9e\u9645\u7684\u57df\u540d/metric/explorer?data_source_id=1&data_source_name=prometheus&mode=graph&prom_ql=cpu_usage_active%7Bident=%22mac-vm-001%22%7D%3E0)"
    }
}
  • payload 是个大 json,里边有两个顶层字段,一个是 event,表示事件内容,一个是 tpls,表示渲染出来的多个模板结果
  • 继续解释那个通知脚本,for ch in payload.get('event').get('notify_channels') 是循环遍历 payload.event.notify_channels,这个字段表示用户在告警规则里勾选的通知媒介列表,是个数组,上例的话,用户只勾选了短信,所以这个数组里只有一个元素,是 sms
  • 然后下面的代码是拼接一个函数名称,最终的效果是,如果 notify_channels 里有 sms 和 voice 两个元素的话,就会以此调用 send_sms 和 send_voice 函数。当然了,上例中 notify_channels 里只有 sms,所以只会调用 send_sms 函数,调用 send_sms 函数的时候,会把整个 payload 作为参数传入
  • 下面我们来具体看一下 send_sms 函数的实现
    @classmethod
    def send_sms(cls, payload):
        users = payload.get('event').get("notify_users_obj")
        phones = {}
        for u in users:
            if u.get("phone"):
                phones[u.get("phone")] = 1
        if phones:
            print("send_sms not implemented, phones: {}".format(phones.keys()))

要发短信,显然需要两个东西,一个是要发给哪些手机号,即手机号列表,另一个是发送的内容。通过解析 notify_users_obj 可以拿到告警接收人的手机号列表,上例中没有演示如何拿到告警模板渲染之后的通知内容,稍后再说。上例中的代码拿到了手机号并打印到 stdout 了,我们直接做个测试,看看日志里能否看到相关的输出。

3. 测试告警

下面我们做个测试。

3.1 配置告警接收人的手机号

要发短信显然是需要手机号的,先把手机号配置好。假设我想把告警发给 root 账号,那就给 root 账号设置一下手机号:

设置手机号

每个人可以设置自己的手机号,入口在页面右上角,点击自己的头像,进入个人信息设置页面即可设置。

3.2 创建告警接收组

夜莺里的告警接收人是通过告警接收组来管理的,所以我们先创建一个告警接收组,然后把 root 加入进去。

告警接收组

之后,我们在告警规则里选择这个告警接收组作为告警接收人。上面的例子中,告警接收组(也叫团队)可以展示为列表形式,也可以展示为树形结构,是在 系统配置-站点设置 里配置的。

站点设置

3.3 创建告警规则

创建一个告警规则,入口在:告警管理-告警规则-新增

告警规则列表

一个公司可能有很多告警规则,为了方便管理,告警规则要归属某个业务组。选中左侧业务组,右侧点击新增即可创建告警规则。如果你看不到业务组列表,要么就是从来都没有创建过业务组,要么是这个区块隐藏了,注意那个收起的 icon,可以通过那个 icon 收起和展开。下面是我创建的告警规则:

告警规则配置

我的版本是 7.7.1,首先设置一下告警规则的标题,然后设置一下该规则要生效的数据源,然后配置 promql、执行频率、持续时长,为了尽快触发,我把 promql 设置成了一个必然会触发的条件,把执行频率调小,把持续时长设置为 0。然后下面的通知媒介勾选了短信,并且选择了一个告警接收组。

3.4 触发告警查看日志

保存之后去查看夜莺的日志。我是 docker compose 部署的,直接使用 docker logs -f nightingale 查看夜莺容器的日志了。稍等片刻,就可以看到夜莺进程调用了脚本,并打印了相关日志:

2024-11-28 09:16:37.890954 DEBUG dispatch/dispatch.go:276 no sender for channel: sms
2024-11-28 09:16:37.958345 INFO sender/plugin.go:108 event_script_notify_ok: exec ./.notify_scriptt output: send_sms not implemented, phones: dict_keys(['18612185520'])

你也可以 grep send,就能看到类似上面的两条日志了。第一条 no sender for channel: sms 表示 n9e 的 go 进程里没有内置 sms 这个通知渠道,所以打印了这么一行 DEBUG,可以忽略无关紧要。第二条日志显示,夜莺的 go 进程调用了 notify_scriptt 脚本(脚本的内容就是页面上填写的那个通知脚本的内容),这个脚本有个输出 output,output 的内容是:send_sms not implemented, phones: dict_keys(['18612185520']),显然这个消息就是刚刚脚本里 print 的内容,一切都符合预期。

4. 继续完善脚本

上面的流程走到现在,其实已经跑通流程了。告警了之后调用了脚本,脚本里调用了 send_sms 函数,send_sms 函数里拿到了手机号。接下来我们要做的是,继续完善 send_sms 函数,把短信模板渲染之后的内容拿到,然后调用短信发送接口发送短信。

获取短信内容其实比较简单,模仿上面获取 notify_channels 的方式:

content = payload.get('tpls').get("sms", "sms template not found")

所以最终的代码类似:

    @classmethod
    def send_sms(cls, payload):
        content = payload.get('tpls').get("sms", "sms template not found")
        users = payload.get('event').get("notify_users_obj")
        phones = {}
        for u in users:
            if u.get("phone"):
                phones[u.get("phone")] = 1
        if phones:
            # 在这个位置调用短信通知接口,把短信内容 content 发给所有的手机号 phones
            # 如果你们的短信通知接口每次只能发送一个手机号,那就遍历 phones,逐个发送

一般短信发送接口都是封装的 HTTP 接口,你可以使用 requests 库调用短信发送接口。这里可能会掉坑。就是你的系统环境里没有 requests 这个 module,你需要安装一下,可以使用 pip 安装:

pip install requests

然后就可以在脚本里使用 requests 了。requests 的使用方法可以参考官方文档:https://docs.python-requests.org/en/latest/

好了,整个流程讲到这里相信你已经可以搞定了。如果你搞定了,真切的恳求你写一篇博客分享一下。因为大家的背景站的角度不同,我们提供的文档和教程有些人可能看不懂,你写的博客可能会帮助到他们,感谢,咱们双赢 :)

快猫星云 联系方式 快猫星云 联系方式
快猫星云 联系方式
快猫星云 联系方式
快猫星云 联系方式
快猫星云
OpenSource
开源版
Flashcat
Flashcat