用python寫一個簡單預警機器人(支持微信和釘釘)

背景

線上的系統在運行中,發生故障時怎麼及時的通過手機通知到相關人員?當然這是個很簡單的需求,現有的方法有很多,例如:

  1. 如果我們用的雲產品,那麼一般都會有配套對應的監控預警功能,根據需要配置一下即可,支持短信,郵箱通知。
  2. 如果我們已經搭建了一套運維監控系統,比如zabbix之類的,那麼我們學會zabbix,然後配置也即可,支持短信,郵箱通知。

但如果我們希望有一個比較簡單輕便,能靈活定製和快速實施的方法,又能同時支持微信和釘釘通知呢?以下就介紹這樣一個基於python的簡單方法,暫且起個名字叫robotprobe。

上路

在開始之前,先定義兩種對象,robotprobe將由這兩種對象組成。

Probe:探針,用於檢查檢測某項功能,某個指標是否正常,幷包含預警相關規則配置。

Robot:機器人,發生異常情況時,要發送通知的對象,這裏特指微信機器人和釘釘機器人。

Probe

class Probe:
    def __init__(self, name, interval=10, threshold=3):
        self.name = name
        #檢測間隔,單位秒
        self.interval = interval
        #當前是否有預警
        self.warning = False
        #預期消息
        self.warning_msg = None
        #預警計數器
        self.warning_counter = 0
        #閾值,預警次數達到閾值時發消息通知
        self.threshold = threshold
        #預警消息模板
        self.warning_msg_tpl = self.name + "預警:%s"

    def test(self):
        print(self.name + " testing")
        self.do_test()
        self.warning = self.warning_counter >= self.threshold
        if self.warning:
            print(self.name + " has warning:" + self.warning_msg)

    def do_test(self):
        raise NotImplementedError

    def consume_warning(self):
        warning_msg = self.warning_msg
        self.warning = False
        self.warning_msg = None
        self.warning_counter = 0
        return warning_msg

UrlProbe

class UrlProbe(Probe):
    def __init__(self, name, interval, threshold):
        super().__init__(name, interval, threshold)
        adapter = SSLAdapter('TLSv1')
        self.session = requests.Session()
        self.session.mount('https://', adapter)

    def do_test(self):
        try:
            self.session.get(self.url, timeout=10)
        except BaseException as e:
            self.warning_counter = self.warning_counter + 1
            self.warning_msg = self.warning_msg_tpl % str(e)
            print(self.warning_msg)

SqlProbe

class SqlProbe(Probe):
    def __init__(self, name, interval, threshold):
        super().__init__(name, interval, threshold)
        db = pymysql.connect(host='localhost', user='root',
                             passwd='xxxx', db='demo', port=3306, charset='utf8',
                             autocommit=True)
        self.cursor = db.cursor()

    def do_test(self):
        try:
            self.cursor.execute(self.sql)
            result = self.cursor.fetchone()
            #當sql查詢的指標大於業務閾值時,發生預警
            if result[0] >= self.biz_threshold:
                self.warning_counter = self.warning_counter + 1
                #biz_tpl可定製業務預警消息模板
                self.warning_msg = self.warning_msg_tpl % (self.biz_tpl % (result[0], self.biz_threshold))
                print(self.warning_msg)
        except BaseException as e:
            self.warning_counter = self.warning_counter + 1
            self.warning_msg = self.warning_msg_tpl % str(e)
            print(self.warning_msg)

其他

其他類型的Probe則可以根據實際需要自由擴展實現。

Robot

class Robot:
    def __init__(self):
        pass

    def send_text(self, msg):
        raise NotImplementedError

WechatRobot

class WechatRobot(Robot):
    def __init__(self, chat_names):
        bot = Bot(console_qr=True, cache_path=True)
        self.chats = bot.search(chat_names)
        super().__init__()

    def send_text(self, msg):
        for chat in self.chats:
            chat.send_msg(msg)

    @staticmethod
    def run_embed():
        ThreadPoolExecutor(1).submit(embed)

DingTalkRobot

class DingTalkRobot(Robot):
    def __init__(self, webhook):
        self.bot = DingtalkChatbot(webhook)
        super().__init__()

    def send_text(self, msg):
        self.bot.send_text(msg, is_at_all=True)

微信VS釘釘

微信機器人基於wxpy實現,wxpy功能很豐富,基本微信上收發消息相關的功能都可以用它來實現,這篇文章有個挺好的使用示例,我們這裏只用到發送消息的功能,微信雖然功能,但有個缺點就是用wxpy發消息(其實是網頁版微信),賬號有可能被封,另外新註冊的微信號也是不能用的。

釘釘機器人基於DingtalkChatbot實現,優點就是官方默認提供機器人的功能,雖然發消息有限制,但一可以控制發消息的頻率,二也可加多個機器人去分流,缺點就是隻能發消息,不收消息,進而根據收到的消息做定製回覆。

Demo示例

import time

import schedule

from probe import UrlProbe, SqlProbe
from robot import DingTalkRobot, WechatRobot

webhook = 'https://oapi.dingtalk.com/robot/send?access_token=xxxxx'
bot = DingTalkRobot(webhook)

# bot = WechatRobot([u"研發部", u"運維部", u"someone you hate"])
# bot.run_embed()

# 每20秒檢測百度網站是否正常,如果不正常超3次,則預警
baidu_probe = UrlProbe("百度", 20, 3)
baidu_probe.url = "https://www.baidux.com"

# 每30秒檢測在線用戶數是否太高,如果不正常達到1次,則預警
online_user_probe = SqlProbe("在線用戶數", 30, 1)
online_user_probe.sql = "select count(1) from online_user"
online_user_probe.biz_threshold = 50000
online_user_probe.biz_tpl = "當前在線用戶數%s,達到閾值%s"

probes = [baidu_probe, online_user_probe]


def notify_latest_state():
    for p in probes:
        if p.warning:
            bot.send_text(p.name + "異常:" + p.warning_msg)
        else:
            bot.send_text(p.name + "正常")


def send_warning(msg):
    bot.send_text(msg)


def trigger_probe(p):
    p.test()
    if p.warning:
        send_warning(p.consume_warning())


schedule.every().day.at("09:00").do(notify_latest_state)

for probe in probes:
    schedule.every(probe.interval).seconds.do(trigger_probe, probe)

if __name__ == '__main__':
    while True:
        schedule.run_pending()
        time.sleep(1)
        print("I am alive!")

依賴

certifi==2019.3.9
chardet==3.0.4
DingtalkChatbot==1.3.0
future==0.17.1
idna==2.8
itchat==1.2.32
PyMySQL==0.9.3
pypng==0.0.19
PyQRCode==1.2.1
requests==2.21.0
requests-toolbelt==0.9.1
schedule==0.6.0
urllib3==1.24.1
wxpy==0.3.9.8

源碼下載

https://github.com/huangyemin/robotprobe
https://gitee.com/huangyemin/robotprobe
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章