调度Job报错或异常触发钉钉报警(Python 3.x版)

525 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

==前 言==

  当例行的Job报错后,大家都希望第一时间得到反馈,或者oncall你手机,或者邮件报警 ,身为阿里系的公司,钉钉当然是首选的交流工具之一,这里介绍一种调度Job报错或者异常触发钉钉报警的Python 3.x脚本;

==钉钉准备==

  首先你得先建个群,群最少三个人,然后点击群助手,添加机器人,具体操作如图1,好了之后群里的机器人会说第一句话 “大家好!我是 贾维斯 机器人,很高兴为你们服务。”,然后你会得到这个机器人的webhook,其实就是一个ulr api,请妥善保管这个机密,而且只有群主,管理员以及创建这个机器人的主人才有权限修改这个机器人,如图2。 在这里插入图片描述

图1 添加机器人贾维斯

在这里插入图片描述

图2 得到机器人的webhook

==核心代码编写==

  核心代码其实就是调用了阿里钉钉的一个api,普通版如下:

def ding_alert(web_hook, ding_text, at_mobile):
    url = web_hook ##刚刚获取的机器人webhook
    msg = {
        "msgtype": "text",
        "text": {"content": ""},
        "at": {"atMobiles": [""], "isAtAll": 0} ##需要@谁查看消息
    } ##msg是个key,values的dictionary
    msg["text"]["content"] = ding_text ##将要发送的消息赋值给message
    if not at_mobile:
        msg["at"]["isAtAll"] = 1  ##=1表示@all
    else:
        msg["at"]["atMobiles"] = "[" + at_mobile + "]"
    headers = {'Content-Type': 'application/json'}
    f = requests.post(url, data=json.dumps(msg), headers=headers)

  有些公司为了安全,生产服务器不提供网络,这时候需要采用能连接外网的代理服务器来代理发送消息,毕竟钉钉本身是外网使用 的,即你在家也能看到钉钉消息,以下是代理服务器版本。

def ding_alert(web_hook, ding_text, at_mobile):
    proxy_host = 10.234.56.78:14531 ##代理服务器端口
    url = web_hook
    msg = {
        "msgtype": "text",
        "text": {"content": ""},
        "at": {"atMobiles": [""], "isAtAll": 0}
    }
    proxies = {
        'http': proxy_host,
        'https': proxy_host
    }
    msg["text"]["content"] = ding_text
    if not at_mobile:
        msg["at"]["isAtAll"] = 1
    else:
        msg["at"]["atMobiles"] = "[" + at_mobile + "]"
    headers = {'Content-Type': 'application/json'}
    f = requests.post(url, data=json.dumps(msg), headers=headers, proxies=proxies)

==封装成完整的代码项目==

  既然调用的参数都是固定的,那么可以把这些参数写到mysql的库里存储,Python读取 mysql即可,所有,首先,建立一个mysql的config库,将这些参web_hook, ding_text, at_mobile等存入config库的cfg_ding_talk_warning_report表,该表的ddl sql语句如下:

CREATE TABLE `cfg_ding_talk_warning_report` (
 `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增id',
 `ding_talk_group_id` bigint(20) NOT NULL COMMENT '钉钉组名id',
 `ding_talk_group_name` varchar(200) NOT NULL COMMENT '钉钉组名',
 `robot_url` varchar(500) NOT NULL COMMENT '机器人ulr',
 `robot_name` varchar(500) DEFAULT NULL COMMENT '机器人名字',
 `warning_report_text` varchar(500) NOT NULL COMMENT '报警内容',
 `at_people_phone` varchar(500) DEFAULT NULL COMMENT '提醒谁看',
 `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
 `create_by` varchar(50) NOT NULL COMMENT '创建人',
 `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
 `update_by` varchar(50) NOT NULL COMMENT '修改人',
 `is_enable` int(11) NOT NULL COMMENT '是否有效',
 `level_desc` varchar(50) NOT NULL COMMENT '紧急等级:普通,中等,紧急',
 PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8

   具体值如图3

在这里插入图片描述

图3 配置表存储信息

   整个项目的排版如图4: 在这里插入图片描述

图4 项目排版树图

   其中配置文件myconfig.ini里面记录的是代理服务器和刚刚说到的存配置信息表 cfg_ding_talk_warning_report的server信息:

[proxy]
proxy_host=agencyserver:port

[mysql_dw_config]
host = prod
port = 3306
user = user
passwd = 
db = config
charset = utf8

  代理版本ding_talk_with_agency

import requests
import configparser
import json
import pymysql
from sqlalchemy import create_engine
import pandas as pd
import sys
import os

def getcon():
    config = configparser.ConfigParser()
    file_path = os.path.dirname(__file__)
    ini_path = "%s/../conf/myconfig.ini"%file_path
    config.read(ini_path)
    config_host = config['mysql_dw_config']["host"]
    config_port = int(config['mysql_dw_config']["port"])
    config_user = config['mysql_dw_config']["user"]
    config_passwd = config['mysql_dw_config']["passwd"]
    config_db = config['mysql_dw_config']["db"]
    config_charset = config['mysql_dw_config']["charset"]
    ## print(config_host+'\t'+config_port+'\t'+config_user+'\t'+config_passwd+'\t'+config_db+'\t'+config_charset)
    try:
        print(1)
        conn = pymysql.Connect(host=config_host, port=config_port, database=config_db, user=config_user,password=config_passwd, charset=config_charset)
        return conn
    except Exception as e:
        print(e)

def ding_alert(web_hook, ding_text, at_mobile):
    config = configparser.ConfigParser()
    file_path = os.path.dirname(__file__)
    ini_path = "%s/../conf/myconfig.ini"%file_path
    config.read(ini_path)
    proxy_host = config['proxy']["proxy_host"]
    url = web_hook
    msg = {
        "msgtype": "text",
        "text": {"content": ""},
        "at": {"atMobiles": [""], "isAtAll": 0}
    }
    proxies = {
        'http': proxy_host,
        'https': proxy_host
    }
    msg["text"]["content"] = ding_text
    if not at_mobile:
        msg["at"]["isAtAll"] = 1
    else:
        msg["at"]["atMobiles"] = "[" + at_mobile + "]"
    headers = {'Content-Type': 'application/json'}
    f = requests.post(url, data=json.dumps(msg), headers=headers, proxies=proxies)

def main(argv):
    myid=int(argv[1])
    dw_config=getcon()
    sqlcmd = """ SELECT * FROM cfg_ding_talk_warning_report WHERE id=%d and is_enable=1"""
    sql1 = sqlcmd % (myid)
    ding_talk_dataframe=pd.read_sql(sql1,dw_config)
    ##print(ding_talk_dataframe)
    if ding_talk_dataframe.empty:
        print("no DingDingTalk Report")
    else:
        url=ding_talk_dataframe['robot_url'].values[0]
        print("url:"+url)
        text=ding_talk_dataframe['robot_name'].values[0]+":"+ding_talk_dataframe['warning_report_text'].values[0]+"    处理等级:"+ding_talk_dataframe['level_desc'].values[0]
        print("text:"+text)
        atMobile=ding_talk_dataframe['at_people_phone'].values[0]
        print("atMobile:"+atMobile)
        ding_alert(url, text, atMobile)

if __name__ == "__main__":
    main(sys.argv)

  非代理版本ding_talk_with_no_agency.py

import requests
import configparser
import json
import pymysql
from sqlalchemy import create_engine
import pandas as pd
import sys
import os

def getcon():
    config = configparser.ConfigParser()
    file_path = os.path.dirname(__file__)
    ini_path = "%s/../conf/myconfig.ini"%file_path
    config.read(ini_path)
    config_host = config['mysql_dw_config']["host"]
    config_port = int(config['mysql_dw_config']["port"])
    config_user = config['mysql_dw_config']["user"]
    config_passwd = config['mysql_dw_config']["passwd"]
    config_db = config['mysql_dw_config']["db"]
    config_charset = config['mysql_dw_config']["charset"]

    ## print(config_host+'\t'+config_port+'\t'+config_user+'\t'+config_passwd+'\t'+config_db+'\t'+config_charset)

    try:
        print(1)
        conn = pymysql.Connect(host=config_host, port=config_port, database=config_db, user=config_user,password=config_passwd, charset=config_charset)
        return conn
    except Exception as e:
        print(e)

def ding_alert(web_hook, ding_text, at_mobile):
    url = web_hook
    msg = {
        "msgtype": "text",
        "text": {"content": ""},
        "at": {"atMobiles": [""], "isAtAll": 0}
    }
    msg["text"]["content"] = ding_text
    if not at_mobile:
        msg["at"]["isAtAll"] = 1
    else:
        msg["at"]["atMobiles"] = "[" + at_mobile + "]"
    headers = {'Content-Type': 'application/json'}
    f = requests.post(url, data=json.dumps(msg), headers=headers)

def main(argv):
    myid=int(argv[1])
    dw_config=getcon()
    sqlcmd = """ SELECT * FROM cfg_ding_talk_warning_report WHERE id=%d and is_enable=1"""
    sql1 = sqlcmd % (myid)
    ding_talk_dataframe=pd.read_sql(sql1,dw_config)
    ##print(ding_talk_dataframe)
    if ding_talk_dataframe.empty:
        print("no DingDingTalk Report")
    else:
        url=ding_talk_dataframe['robot_url'].values[0]
        print("url:"+url)
        text=ding_talk_dataframe['robot_name'].values[0]+":"+ding_talk_dataframe['warning_report_text'].values[0]+"    处理等级:"+ding_talk_dataframe['level_desc'].values[0]
        print("text:"+text)
        atMobile=ding_talk_dataframe['at_people_phone'].values[0]
        print("atMobile:"+atMobile)
        ding_alert(url, text, atMobile)

if __name__ == "__main__":
    main(sys.argv)

  调用脚本

##后面的1表示配置表里面的主键id
python ding_talk_with_agency.py 1  ##代理版本
python ding_talk_with_no_agency.py 1  ##非代理版本

  整个项目已经备份上传至git hub,版权所有,欢迎借鉴,地址链接 :dingding_talk_report