如何优雅地用Python3发送Zabbix告警推送

简介: 如何让Zabbix告警推送出来的消息内容具有可读性、易识别?比如故障时是红色标题,恢复时是绿色标题,监控项目之间要有换行,清晰可辨。在这里我分享一下我的思路,在这个小项目中我们统一使用Python3来发送消息,并且实现了推送到Exchange、钉钉、企业微信、自研IM多种消息平台。

如何让Zabbix告警推送出来的消息内容具有可读性、易识别?比如故障时是红色标题,恢复时是绿色标题,监控项目之间要有换行,清晰可辨。在这里我分享一下我的思路,在这个小项目中我们统一使用Python3来发送消息,并且实现了推送到Exchange、钉钉、企业微信、自研IM多种消息平台。

首先,我们先来看一下Zabbix 消息内容加了样式后的效果

Exchange样式

告警 如图1

104.png

如图 1

恢复 如图2

0.png


如图 2


企业微信样式

告警 如图3

1.png

如图 3

恢复 如图4

2.png

如图 4

钉钉样式

告警 如图5

3.png


如图 5

恢复 如图6

微信图片_20220311140019.png

如图 6

源码逻辑

以上效果基本实现了我们的预期,接下来,讲讲实现逻辑吧,比较简单,先把动作里传过来的字符串转为字典,再进行数据重组,添加html或markdown样式,发送给各个消息平台。


微信图片_20220311140040.png


图 7

在这里讲讲实现过程中的3个问题吧。问题1.为什么要把消息内容转成dict而不是json对象?因为在python中对json做处理,value外层必须用双引号,但是实际测试,发现zabbix的原消息内容里带有双引号,会和json的外层双引号冲突,于是动作的消息内容字符串外层改用单引号。dict支持单引号,所以处理成dict更合适。

问题2. 样式为什么写在了脚本里,而不是动作的消息内容里?样式确实可以直接在动作的消息内容里添加,比如配置xml,html,纯文本很容易,但是markdown 很容易搞成一团,发送出来的内容没有换行,所以建议把样式写到了脚本里。

问题3. token 或key收件人还是脚本里好?如果要复用脚本,写到收件人里更好,比如群机器人比较多时这种情况下,多个token可以复用/usr/lib/zabbix/alertscripts/下的同一个脚本。当然,如果只有一个群机器人的话,写到哪都比较方便,看个人习惯而言。

在这里我们以企业微信为例,说说具体流程,当zabbix的字符串消息通过位置参数传给脚本send-wework-problems.py后,ast.literal_eval()函数接受参数并转为字典类型,以便进行数据重组,使用join()函数进行字符串拼接,加入markdown样式,加入换行,完成数据重组。企业微信字体支持3种内置颜色,markdown语法如下:

<fontcolor="info">绿色</font>
<fontcolor="comment">灰色</font>
<fontcolor="warning">橙红色</font>

我们使用橙红色作为 告警消息标题颜色样式,使用绿色作为恢复消息标题颜色样式,发送请求代码如下:

#!/usr/bin/env python3
import requests
import os
import sys
import logging
import json
import urllib3
import ast
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
logging.basicConfig(filename = os.path.join(os.getcwd(), 'push.log'), level = logging.INFO,format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
subject = sys.argv[1]
data = sys.argv[2]
# 把字符串转为字典
message  = ast.literal_eval(data)
# 测试用
#filename = '/usr/lib/zabbix/alertscripts/1.txt'
#with open(filename, 'w') as file_object:
#    file_object.write(data)
HOSTNAME = ': '.join(('> 告警主机',message["HOSTNAME"]))
HOSTIP = ': '.join(('告警地址',message["HOSTIP"]))
ITEMNAME = ': '.join(('监控项目',message["ITEMNAME"]))
ITEMLASTVALUE = ': '.join(('监控取值',message["ITEMLASTVALUE"]))
TRIGGERSEVERITY = ': '.join(('告警等级',message["TRIGGERSEVERITY"]))
TRIGGERSTATUS = ': '.join(('当前状态',message["TRIGGERSTATUS"]))
TRIGGERNAME = ': '.join(('告警信息',message["TRIGGERNAME"]))
EVENTTIME = ': '.join(('告警时间',message["EVENTTIME"]))
EVENTAGE = ': '.join(('持续时间',message["EVENTAGE"]))
EVENTID = ': '.join(('事件ID',message["EVENTID"]))
sendtext = '\n >'.join((HOSTNAME,HOSTIP,ITEMNAME,ITEMLASTVALUE,TRIGGERSEVERITY,TRIGGERSTATUS,TRIGGERNAME,EVENTTIME,EVENTAGE,EVENTID))
# 请修改key, zabbix server url
def send_wework_message(sendtext):
    logger = logging.getLogger(__name__)
    WEWORK_API_URL="https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=x"
    data = {
'msgtype': 'markdown',
"markdown": {
"content": ''.join(('## <font color="warning">',subject,'</font> \n',sendtext,'\n','#### [点击转到ZABBIX](https://www.zabbix.com/) \n'))
}
}
    resp = requests.post(
        WEWORK_API_URL, data=json.dumps(data), headers={'Content-Type': 'application/json'}
)
print(resp.text)
if resp.status_code != 200:
        logger.info('[REQUESTS WEWORK API ERROR]%s'% resp.text)
send_wework_message(sendtext)

企业微信消息发送可以参考https://work.weixin.qq.com/help?doc_id=13376#如何使用群机器人

其他类型的我都放到了github上,见https://github.com/ZuoGuocai/zabbix_push

开始配置

需要先把send-problems-wework.py,send-recovery- wework.py两个脚本放在zabbix server 的/usr/lib/zabbix/alertscripts 目录下,这两个脚本功能分别对应告警推送,恢复推送。

管理--报警媒介类型--创建媒体类型

4.png


如图 8

在这里我把key放到了脚本里,收件人里配置了一个无用的字符串,所以没有添加{ALERT.SENDTO},只有如下两项

{ALERT.SUBJECT}
{ALERT.MESSAGE}

如果要复用脚本,建议配置以下三项

ALERT.SENDTO}
{ALERT.SUBJECT}
{ALERT.MESSAGE}


管理--用户--Admin--报警媒介--添加--收件人

5.png


配置--主机--监控项和触发器,再配置动作

为了方便演示,我配置了一台主机,添加了Zabbix 原生的ICMP Ping模板,自带了监控项和触发器 。

开始配置动作

6.png

如图10

消息内容如下

{
"HOSTNAME":"{HOST.NAME}",
"HOSTIP":"{HOST.IP}",
"ITEMNAME":'{ITEM.NAME}',
"ITEMLASTVALUE":"{ITEM.LASTVALUE}",
"TRIGGERSEVERITY":"{TRIGGER.SEVERITY}",
"TRIGGERSTATUS":"{TRIGGER.STATUS}",
"TRIGGERNAME":"{TRIGGER.NAME}",
"EVENTTIME":"{EVENT.DATE} {EVENT.TIME}",
"EVENTAGE":"{EVENT.AGE}",
"EVENTID":"{EVENT.ID}"
}

有没有发现第三项的value外层是单引号,value里经常有双引号出现,所有外层改用了单引号。这儿很好解释了 问题1.为什么要把消息内容转成dict而不是json对象

开始测试

在监测主机上操作

禁止ping

echo 1>/proc/sys/net/ipv4/icmp_echo_ignore_all

查看告警消息

允许ping

1. echo 0>/proc/sys/net/ipv4/icmp_echo_ignore_all

查看恢复消息

排错

告警消息为什么没有发出,脚本执行报错,为了更好的排错,建议添加动作日志,在web控制台的路径如下

监测--仪表盘--编辑仪表盘--添加构件--类型--动作日志

7.png




如图11

爱美之心,人皆有之,用Python3改写样式后,Zabbix发送的告警消息简洁优雅,并且能很好地跟多种IM集成,不禁感慨,这才是我要的告警效果呀。

本文作者:左国才,VIPKID运维工程师,笔名icai,主要研究开源Linux操作系统,数据库,云计算领域相关技术,平时喜欢阅读脚本之家公众号。

声明:本文为 脚本之家专栏作者 投稿,未经允许请勿转载。

相关文章
|
监控 机器人 Python
Zabbix实现钉钉群告警
Zabbix实现钉钉群告警
|
JSON 监控 前端开发
python对接API二次开发高级实战案例解析:Zabbix API封装类实现获取认证密钥、所有主机组、所有主机、所有监控项和历史数据
python对接API二次开发高级实战案例解析:Zabbix API封装类实现获取认证密钥、所有主机组、所有主机、所有监控项和历史数据
531 0
|
消息中间件 存储 运维
Zabbix与ELK整合实现对安全日志数据的实时监控告警
Zabbix与ELK整合实现对安全日志数据的实时监控告警
Zabbix与ELK整合实现对安全日志数据的实时监控告警
|
5月前
|
监控
一文吃透企业级elk技术栈:9. zabbix结合logstash告警
一文吃透企业级elk技术栈:9. zabbix结合logstash告警
|
监控 机器人 开发工具
python监控脚本外发钉钉告警
python监控脚本外发钉钉告警
217 1
|
监控 安全 Ubuntu
用python部署zabbix
用python部署zabbix
135 1
|
监控 NoSQL Redis
【Zabbix】Zabbix微信告警配置演示(下)
【Zabbix】Zabbix微信告警配置演示(下)
161 0
|
监控
【Zabbix】Zabbix微信告警配置演示(上)
【Zabbix】Zabbix微信告警配置演示
173 0
|
监控 机器人 定位技术
ZABBIX4.0 微信告警
ZABBIX4.0 微信告警
170 0
ZABBIX4.0 微信告警
|
运维 监控 定位技术
ZABBIX4.0配置邮箱告警信息发送给用户组
ZABBIX4.0配置邮箱告警信息发送给用户组
227 0
ZABBIX4.0配置邮箱告警信息发送给用户组