python监听WebSocket并实现故障告警以及自动恢复告警

python监听WebSocket并实现故障告警以及自动恢复告警

背景

对腾讯云云监控以及云拔测的功能补充

环境

  1. python
    python版本
  2. swoole
    Swoole官方介绍
  3. WebSocket服务器 A 、监听WebSocket服务器的python代码执行服务器 B
  4. B 服务器安装 websocket-client==0.55.0
  5. 网易126邮箱的第三方授权密码。

过程

  1. 利用Swoole在远程服务器 A 启动WebSocket服务。
    Swoole 网址:https://www.swoole.com/
    Swoole安装 略
<?php
$server = new swoole_websocket_server("0.0.0.0", 9502);

$server->on('open', function($server, $req) {
    $server->push($req->fd, json_encode([40311, '']));
    echo "connection open: {$req->fd}\n";
});

$server->on('message', function($server, $frame) {
    echo "received message: {$frame->data}\n";
    $server->push($frame->fd, json_encode(["hello", "world"]));
});

$server->on('close', function($server, $fd) {
    echo "connection close: {$fd}\n";
});

$server->start();

将以上代码保存ws.php 并执行 php ws.php 即可启动WebSocket服务
备注:

$server->push($req->fd, json_encode([40311, '']));

此行代码是手动添加的,目的是在成功连接WebSocket服务器之后可接收的返回值。这里的返回值定义的是 [40311, ‘’]
在生产环境中,要跟研发同事对接好在成功连接WebSocket服务之后服务器返回值是多少。然后修改代码config.py内的字典对应值。

2. 在 B 服务器下载或粘贴我的源码,以下是我的代码总览
代码总览
3. 在代码所在目录执行 python Main.py 即可循环监听config模块内字典配置的ws服务端

源码

Main.py

#!/usr/bin/env python
#-*-coding:UTF-8-*-
__author__ = '于洪超'
import os, commands



PythonPath = commands.getstatusoutput('which python')[1]
SetSidPath = commands.getstatusoutput('which setsid')[1]
CodePath = os.path.dirname(os.path.realpath(__file__)) + '/'


MonitorWSSFileName = 'MonitorWSS.py'


def MainMonitor():

    CmdMonitorWss = "%s %s %s%s >> /dev/null 2>&1 &" % (SetSidPath, PythonPath, CodePath, MonitorWSSFileName)
    if os.system(CmdMonitorWss) == 0:
        print("\033[32m监控WS站点状态代码 %s 启动成功!\033[0m" % MonitorWSSFileName)
    else:
        print("\033[31m监控WS站点状态代码 %s 启动失败!\033[0m" % MonitorWSSFileName)


if __name__ == '__main__':
    MainMonitor()

config.py

#!/usr/bin/env python
#-*-coding:UTF-8-*-


# 监控字典k:监听URL v: [预期返回值, 访问超时时间, 监听频率(秒), 最大告警次数n]
MonitorDict = {

                'wss://xxx.xxx.xxx/wss': ['[40311,""]', 5, 5, 2],
                'ws://xx.xx.xx.xx:9502': ['[40311,""]', 5, 2, 3],

               }

# 发送邮件相关配置
ForSendMess = {

    'from': 'xxxxxxxx@126.com',
    'password': 'xxxxxxxxxx',
    'smtp_server': 'smtp.126.com',
    'TOLIST': ['xxxxxxxx@126.com', 'xxxxx@qq.com', ],

               }

备注:
需要注意的是 发送邮件相关配置 ForSendMess 字典里 password 这个key的value 是126网易邮箱的第三方授权密码。而不是邮箱密码。此授权密码可以在邮箱设置处设置。
MonitorDict 字典里的 预期返回值逗号后面不能有空格
MonitorWSS.py

#!/usr/bin/env python
#-*-coding:utf-8-*-
from websocket import create_connection
import time
import threading
import SendMess
from config import MonitorDict

# 监听的WSS URL个数
monitorWSScount = len(MonitorDict.keys())

def MonitorWss(i):
    sended = 0
    while True:
        k = MonitorDict.keys()[i]
        v = MonitorDict.get(k)
        time.sleep(v[2])

        try:
            ws = create_connection(k, timeout=v[1])
            if ws.connected:
                if ws.recv() == v[0]:
                    print "%s %s" % (k, 'connected successfully !')
                    ws.close()
                    if sended != 0:
                        senContent = "%s 当前返回值:%s" % (k, v[0])
                        SendMess.sendmessage(k, senContent, 'success')
                        sended = 0

                    continue

        except Exception as e:
            # print(str(e))
            sended += 1
            # print str(sended) + '=============='
            if sended < v[3]:
                SendMess.sendmessage(k, str(e), 'failure')
            elif sended == v[3]:
                SendMess.sendmessage(k, str(e), 'failure', 'high', '1')
            elif sended > v[3]:
                sended = v[3] + 1
                print("已经到达最大告警邮件配置,不再发送邮件!")




# 多线程实现
def main(thread_num):
    threadingPool = []
    for i in xrange(thread_num):
        threadingPool.append(threading.Thread(target=MonitorWss, args=(i, )))
    for th in threadingPool:
        th.setDaemon(True)
        th.start()
    for th in threadingPool:
        threading.Thread.join(th)



if __name__ == '__main__':
    main(monitorWSScount)



SendMess.py

#!/usr/bin/python
#-*-coding:UTF-8-*-

from __future__ import print_function
import smtplib
from email.header import Header
from email.mime.text import MIMEText
from email.utils import parseaddr, formataddr

from config import  ForSendMess



import sys
reload(sys)
sys.setdefaultencoding('utf-8')

from_addr = ForSendMess.get('from')
password = ForSendMess.get('password')
smtp_server = ForSendMess.get('smtp_server')
TOLIST = ForSendMess.get('TOLIST')


def _format_addr(s):
    name, addr = parseaddr(s)
    return formataddr(( \
        Header(name, 'utf-8').encode(), \
        addr.encode('utf-8') if isinstance(addr, unicode) else addr
    )
    )


def sendmessage(WSSNAME, arg2 = '', arg3 = '', arg4 = '', arg5 = ''):
    SUBJECT_DOWN = "WS站点:%s 状态异常!请检查!" % WSSNAME
    SUBJECT_UP = "WS站点:%s 状态恢复健康!" % WSSNAME

    text = "WS站点:%s\r\n信息:%s" % (WSSNAME, arg2)  # 定义邮件内容

    for to_addr in TOLIST:
        if arg3 == 'success':
            SUBJECT = SUBJECT_UP
        if arg3 == 'failure':
            SUBJECT = SUBJECT_DOWN


        msg = MIMEText(text, 'plain', 'utf-8')
        msg['From'] = _format_addr(u'Davide <%s>' % from_addr)
        msg['To'] = _format_addr(u'管理员 <%s>' % to_addr)
        msg['Subject'] = Header(u'%s' % SUBJECT, 'utf-8').encode()

        # 紧急
        level_client = arg4
        level_browser = arg5
        if level_client:
            msg['Importance'] = level_client
        if level_browser:
            msg['X-Priority'] = level_browser

        server = smtplib.SMTP(smtp_server, 25)
        server.set_debuglevel(1)
        server.login(from_addr, password)
        server.sendmail(from_addr, [to_addr], msg.as_string())
        server.quit()

shutdown.py

#!/usr/bin/env python
#-*-coding:UTF-8-*-
__author__ = '于洪超'


import commands
import sys
#Main.py开启的进程ID列表

cmd1 = "ps -ef |grep MonitorWSS |grep -v grep|awk '{print $2}'"
pList_Main_WS = commands.getstatusoutput(cmd1)[1].split('\n')
pList = pList_Main_WS

def killAll():
    for p in pList:
        cmd = "kill %s" % p
        if commands.getstatusoutput(cmd)[0] == 0:
            pass
        else:
            sys.exit("无法杀死 %s ID进程!" % p)

killAll()


备注:
执行python shutdown.py 关闭循环监听。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

于特洛夫斯基

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值