在zabbix中实现发送带有图片的邮件和微信告警
1 python实现在4.2版本zabbix发送带有图片的报警邮件
我们通常收到的报警,都是文字,是把动作中的消息内容当成了正文参数传给脚本,然后邮件或者微信进行接收,往往只能看到当前值,无法直观的获取到历史当天该监控项的运行曲线图,因此根据此需求,使用python编写脚本来分别对邮件告警和微信告警,进行升级,报警内容中加入了当天的历史趋势图,功夫不负有心人,已成功解锁,并实践成功,因此分享出来供大家参考,另外得非常感谢脚本编写中刚哥大神和王二基友给予的帮助
1.1 实现思路
-
首先报警信息里第一行要有itemid,这是前提,根据信息里传入的参数使用正则匹配到itemid
-
使用脚本创建一个zabbix会话,来根据itemid来获取图片,并将获取到的图片保存到本地
-
将传入的参数信息的text字段转换成HTML格式,然后将HTML格式的信息和图片作为邮件进行发送
1.2 准备环境
-
脚本是使用python脚本,运行环境为python 2.7.5
-
依赖库:
requests
1.3 脚本实现
1 [root@5804703917ad zabbix]# cd /usr/lib/zabbix/alertscripts/ #进入zabbix默认的脚本路径 2 [root@5804703917ad alertscripts]# mkdir graph #创建一个存放图片的文件夹 3 [root@5804703917ad alertscripts]# chmod 777 graph #给文件夹赋予权限 4 [root@5804703917ad alertscripts]# vim zabbix_email_pic.py #编写实现脚本 5 #!/usr/bin/python 6 #coding=utf-8 7 from email.mime.text import MIMEText 8 from email.mime.multipart import MIMEMultipart 9 from email.mime.image import MIMEImage 10 import smtplib,sys,os,time,re,requests 11 from smtplib import SMTP 12 13 user='Admin' #定义zabbix用户名 14 password='zabbix' #定义zabbix用户密码 15 graph_path='/usr/lib/zabbix/alertscripts/graph' #定义图片存储路径 16 graph_url='http://192.168.73.133/chart.php' #定义图表的url 17 loginurl="http://192.168.73.133/index.php" #定义登录的url 18 host='192.168.73.133' 19 to_email=sys.argv[1] #传入的第一个参数为收件人邮箱 20 subject=sys.argv[2] #传入的第二个参数为邮件主题 21 subject=subject.decode('utf-8') 22 smtp_host = 'smtp.163.com' #定义smtp主机地址 23 from_email = 'xxxx@163.com.cn' #定义发件人地址 24 mail_pass = 'xxx' #发件人邮箱校验码 25 26 def get_itemid(): 27 #获取报警的itemid 28 itemid=re.search(r'监控ID:(\d+)',sys.argv[3]).group(1) 29 return itemid 30 31 def get_graph(itemid): 32 #获取报警的图表并保存 33 session=requests.Session() #创建一个session会话 34 try: 35 loginheaders={ 36 "Host":host, 37 "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8" 38 } 39 #定义请求消息头 40 41 payload = { 42 "name":user, 43 "password":password, 44 "autologin":"1", 45 "enter":"Sign in", 46 } 47 #定义传入的data 48 login=session.post(url=loginurl,headers=loginheaders,data=payload) 49 #进行登录 50 graph_params={ 51 "from" :"now-10m", 52 "to" : "now", 53 "itemids" : itemid, 54 "width" : "400", 55 } 56 #定义获取图片的参数 57 graph_req=session.get(url=graph_url,params=graph_params) 58 #发送get请求获取图片数据 59 time_tag=time.strftime("%Y%m%d%H%M%S", time.localtime()) 60 graph_name='baojing_'+time_tag+'.png' 61 #用报警时间来作为图片名进行保存 62 graph_name = os.path.join(graph_path, graph_name) 63 #使用绝对路径保存图片 64 with open(graph_name,'wb') as f: 65 f.write(graph_req.content) 66 #将获取到的图片数据写入到文件中去 67 return graph_name 68 69 except Exception as e: 70 print(e) 71 return False 72 def text_to_html(text): 73 #将邮件内容text字段转换成HTML格式 74 d=text.splitlines() 75 #将邮件内容以每行作为一个列表元素存储在列表中 76 html_text='' 77 for i in d: 78 i='' + i + '<br>' 79 html_text+=i + '\n' 80 #为列表的每个元素后加上html的换行标签 81 return html_text 82 83 def send_mail(graph_name): 84 #将html和图片封装成邮件进行发送 85 msg = MIMEMultipart('related') #创建内嵌资源的实例 86 87 with open(graph_name,'rb') as f: 88 #读取图片文件 89 graph=MIMEImage(f.read()) #读取图片赋值一个图片对象 90 graph.add_header('Content-ID','imgid1') #为图片对象添加标题字段和值 91 text=text_to_html(sys.argv[3]) 92 html=""" 93 <html> 94 <body> 95 %s <br><img src="cid:imgid1"> 96 </body> 97 </html> 98 """ % text 99 html=MIMEText(html,'html','utf-8') #创建HTML格式的邮件体 100 msg.attach(html) #使用attach方法将HTML添加到msg实例中 101 msg.attach(graph) #使用attach方法将图片添加到msg实例中 102 msg['Subject'] = subject 103 msg['From'] = from_email 104 try: 105 server=SMTP(smtp_host,"587") #创建一个smtp对象 106 server.starttls() #启用安全传输模式 107 server.login(from_email,mail_pass) #邮箱账号登录 108 server.sendmail(from_email,to_email,msg.as_string()) #发送邮件 109 server.quit() #断开smtp连接 110 except smtplib.SMTPException as a: 111 print(a) 112 113 def run(): 114 itemid=get_itemid() 115 graph_name=get_graph(itemid) 116 send_mail(graph_name) 117 118 if __name__ =='__main__': 119 run()
1.4 定义报警媒介类型
-
打开zabbix监控web,在管理菜单中选择报警媒介类型,创建媒体类型,选择脚本,填写刚才编写的邮件带图脚本名称zabbix_email_pic.py,脚本参数,最后添加
-
打开管理中的用户,点击需要设置邮件告警的用户,然后在报警媒介中添加报警媒介,在弹框中选择刚才定义的类型,然后填写想要发送的邮箱地址,最后添加
1.5 定义告警动作
-
点击配置菜单中的动作,创建动作,然后根据图片进行填写
操作
默认标题 Zabbix告警:服务器:{HOSTNAME}发生: {TRIGGER.NAME}故障!
监控ID:{ITEM.ID}
告警主机:{HOST.NAME}
告警主机:{HOST.IP}
告警时间:{EVENT.DATE} {EVENT.TIME}
告警等级:{TRIGGER.SEVERITY}
告警信息: {TRIGGER.NAME}
告警项目:{TRIGGER.KEY}
问题详情:{ITEM.NAME}:{ITEM.VALUE}
当前状态:{TRIGGER.STATUS}:{ITEM.VALUE}
事件ID:{EVENT.ID}
恢复操作
Zabbix告警:服务器:{HOST.NAME}发生: {TRIGGER.NAME}已恢复!
监控ID:{ITEM.ID}
告警主机:{HOST.NAME}
告警主机:{HOST.IP}
告警时间:{EVENT.DATE} {EVENT.TIME}
告警等级:{TRIGGER.SEVERITY}
告警信息: {TRIGGER.NAME}
告警项目:{TRIGGER.KEY}
1.6 最终效果
可以手动触发一个报警测试效果
2 python实现在4.2版本zabbix发送带有图片的微信告警
2.1 实现思路
-
首先创建企业公众号获取agentId,secret和部门id
-
然后根据报警信息获取itemid,使用正则匹配到itemid
-
使用脚本创建一个zabbix会话,来根据itemid来获取图片,并将获取到的图片保存到本地
-
调用企业微信api接口,把图片当成临时素材上传,返回一个media_id,给发送消息和图片调用使用,最后使用mpnews消息类型把图片和报警内容进行推送到微信上
2.2 准备环境
-
脚本是使用python脚本,运行环境为python 2.7.5
-
依赖库提前安装:
requests
2.3 创建企业公众号获取agentid,secret
这部分内容,可以查看前面不带图的文章有详细描述
2.4 脚本实现
1 [root@5804703917ad zabbix]# cd /usr/lib/zabbix/alertscripts/ #进入zabbix默认的脚本路径 2 [root@5804703917ad alertscripts]# mkdir graph #创建一个存放图片的文件夹 3 [root@5804703917ad alertscripts]# chmod 777 graph #给文件夹赋予权限 4 [root@5804703917ad alertscripts]# vim zabbix_weixin_pic.py #编写实现脚本 5 #!/usr/bin/python 6 #coding=utf-8 7 _author__ = 'zhangdongdong' 8 import requests, json 9 import urllib3 10 import smtplib,sys,os,time,re,requests 11 from email.mime.image import MIMEImage 12 if sys.getdefaultencoding() != 'utf-8': 13 reload(sys) 14 sys.setdefaultencoding('utf-8') 15 urllib3.disable_warnings() 16 class WechatImage(object): # 根据企业微信api接口文档,定义一个类,使用mpnews类型,https://qydev.weixin.qq.com/wiki/index.php?title=%E6%B6%88%E6%81%AF%E7%B1%BB%E5%9E%8B%E5%8F%8A%E6%95%B0%E6%8D%AE%E6%A0%BC%E5%BC%8F 17 18 def get_token(self, corpid, secret): # 获取token 19 url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken" 20 data = {"corpid": corpid, 21 "corpsecret": secret} 22 r = requests.get(url=url, params=data, verify=False) 23 token = r.json()['access_token'] 24 return token 25 26 def get_image_url(self, token, path): # 上传临时素材图片,然后返回media_id 27 url = "https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token=%s&type=image" % token 28 data = {"media": open(path, 'rb')} 29 r = requests.post(url=url, files=data) 30 dict_data = r.json() 31 return dict_data['media_id'] 32 def get_messages( self,subject,content,path): #定义mpnews类型中的参数字典 33 data = '' 34 messages = {} 35 body = {} 36 content_html=text_to_html(content) 37 token = self.get_token(corpid, secret) 38 image = self.get_image_url(token, path) 39 content_html += "<br/> <img src='https://qyapi.weixin.qq.com/cgi-bin/media/get?access_token=%s&media_id=%s'>" % (token, image) 40 body["title"] = subject 41 body['digest'] = content 42 body['content'] = content_html 43 body['thumb_media_id'] = image 44 data = [] 45 data.append(body) 46 messages['articles'] = data 47 return messages 48 def send_news_message(self, corpid, secret,to_user, agentid,path): #定义发送mpnews类型的数据 49 token = self.get_token(corpid, secret) 50 messages = self.get_messages( subject, content,path) 51 url = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=%s" % token 52 data = {"toparty": to_user, # 企业号中的用户帐号 53 "agentid": agentid, # 企业号中的应用id 54 "msgtype": "mpnews", 55 "mpnews": messages, 56 "safe": "0"} 57 headers = {'content-type': 'application/json'} 58 data_dict = json.dumps(data, ensure_ascii=False).encode('utf-8') 59 r = requests.post(url=url, headers=headers, data=data_dict) 60 return r.text 61 def text_to_html(text): #将邮件内容text字段转换成HTML格式 62 d=text.splitlines() 63 #将邮件内容以每行作为一个列表元素存储在列表中 64 html_text='' 65 for i in d: 66 i='' + i + '<br>' 67 html_text+=i + '\n' 68 #为列表的每个元素后加上html的换行标签 69 return html_text 70 def get_itemid(): 71 #获取报警的itemid 72 itemid=re.search(r'监控ID:(\d+)',sys.argv[3]).group(1) 73 return itemid 74 def get_graph(itemid): 75 #获取报警的图表并保存 76 session=requests.Session() #创建一个session会话 77 try: 78 loginheaders={ 79 "Host":host, 80 "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8" 81 } 82 #定义请求消息头 83 84 payload = { 85 "name":user, 86 "password":password, 87 "autologin":"1", 88 "enter":"Sign in", 89 } 90 #定义传入的data 91 login=session.post(url=loginurl,headers=loginheaders,data=payload) 92 #进行登录 93 graph_params={ 94 "from" :"now-10m", 95 "to" : "now", 96 "itemids" : itemid, 97 "width" : "290", #图片的高宽参数可以自行调整 98 "height" : "40", 99 } 100 #定义获取图片的参数 101 graph_req=session.get(url=graph_url,params=graph_params) 102 #发送get请求获取图片数据 103 time_tag=time.strftime("%Y%m%d%H%M%S", time.localtime()) 104 graph_name='baojing_'+time_tag+'.png' 105 #用报警时间来作为图片名进行保存 106 graph_name = os.path.join(graph_path, graph_name) 107 #使用绝对路径保存图片 108 with open(graph_name,'wb') as f: 109 f.write(graph_req.content) 110 #将获取到的图片数据写入到文件中去 111 return graph_name 112 except Exception as e: 113 print(e) 114 return False 115 if __name__ == '__main__': 116 user='Admin' #定义zabbix用户名 117 password='zabbix' #定义zabbix用户i密 118 graph_path='/usr/lib/zabbix/alertscripts/graph/' #定义图片存储路径,图片需要定时清理 119 graph_url='http://192.168.73.133/chart.php' #定义图表的url 120 loginurl="http://192.168.73.133/index.php" #定义登录的url 121 host='192.168.73.133' 122 itemid=get_itemid() 123 path =get_graph(itemid) 124 to_user = str(sys.argv[1]) 125 subject = str(sys.argv[2]) 126 content = str(sys.argv[3]) 127 corpid= "xxxxx" 128 secret = "xxxxxxx" 129 agentid = "1000002" 130 wechat_img = WechatImage() 131 wechat_img.send_news_message(corpid, secret,to_user, agentid, path)
-
打开zabbix监控web,在管理菜单中选择报警媒介类型,创建媒体类型,选择脚本,填写刚才编写的微信带图脚本名称zabbix_weixin_pic.py,脚本参数,最后添加
-
打开管理中的用户,点击需要设置邮件告警的用户,然后在报警媒介中添加报警媒介,在弹框中选择刚才定义的类型,然后填写企业微信中创建的部门id,最后添加
2.6 定义告警动作
-
点击配置菜单中的动作,创建动作,然后根据图片进行填写
操作
默认标题 Zabbix告警:服务器:{HOSTNAME}发生: {TRIGGER.NAME}故障!
监控ID:{ITEM.ID}
告警主机:{HOST.NAME}
告警主机:{HOST.IP}
告警时间:{EVENT.DATE} {EVENT.TIME}
告警等级:{TRIGGER.SEVERITY}
告警信息: {TRIGGER.NAME}
告警项目:{TRIGGER.KEY}
问题详情:{ITEM.NAME}:{ITEM.VALUE}
当前状态:{TRIGGER.STATUS}:{ITEM.VALUE}
事件ID:{EVENT.ID}
恢复操作
Zabbix告警:服务器:{HOST.NAME}发生: {TRIGGER.NAME}已恢复!
监控ID:{ITEM.ID}
告警主机:{HOST.NAME}
告警主机:{HOST.IP}
告警时间:{EVENT.DATE} {EVENT.TIME}
告警等级:{TRIGGER.SEVERITY}
告警信息: {TRIGGER.NAME}
告警项目:{TRIGGER.KEY}
问题详情:{ITEM.NAME}:{ITEM.VALUE}
当前状态:{TRIGGER.STATUS}:{ITEM.VALUE}
事件ID:{EVENT.ID}
2.7 测试效果
可以手动触发一个报警测试效果,手机上就可以收到带图的报警了,点击消息之后的页面也可以看到历史的图片
欢迎填加微信公众号,大家共同交流,共同进步