十、企业微信发送Zabbix报警图文信息

概要

入职之后,邮箱正常的业务邮件没几个,倒是每天被几百封Zabbix的报警邮件充斥,不仅杂乱无章,而且也不是那么愿意去看每封邮件的内容,刚好公司在用企业微信,所以打算把Zabbix的报警信息迁移到企业微信上去,大致思路如下:

  • 高等级的报警信息,以图文格式发送报警内容和ITEM一个小时之内的趋势图
  • 较低等级的报警信息,以卡片格式的消息发送(纯文本消息太丑)
  • 以小时为单位整理出还在PROBLEM状态的EVENT告知管理员

实现过程

#!/usr/local/bin/python
# -*- coding:utf-8 -*-
# name image.py
from selenium import webdriver
import os
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

def get_item_graph(itemid,flag,eventid):
    temp_name = "/tmp/"+eventid+".png"
        #save_screenshot仅能保存png格式图片,所以文件名定义需要以png结尾
    driver = webdriver.PhantomJS("/usr/local/zabbix-agent-ops/phantomjs-2.1.1/bin/phantomjs",service_log_path=os.path.devnull)
        #使用PhantomJS可以模拟浏览器进行访问
    driver.get("http://127.0.0.1/zabbix/")
    driver.set_window_size(640,480)
    driver.find_element_by_id("name").send_keys("armo")
    driver.find_element_by_id("password").send_keys("123456")
    driver.find_element_by_id("enter").click()
        #模拟访问url,在对应的元素element处输入用户名密码后click登陆
    if flag:
        driver.get("http://127.0.0.1/zabbix/history.php?action=showgraph&fullscreen=1&itemids[]="+itemid)
    else:
        driver.get("http://127.0.0.1/zabbix/history.php?action=showvalues&fullscreen=1&itemids[]="+itemid)
        #flag如果是1,则对应Item有对应的graph获取;如果是0,则获取最新一段时间的值
        driver.save_screenshot(temp_name)
        #将网页内容保存为png图片
    driver.close()
    driver.quit()

if __name__ == "__main__":
    if len(sys.argv) > 1:
        itemid = sys.argv[1]           #脚本传递的第一个参数 Item ID
        flag = sys.argv[2]             #脚本传递的第二个参数 Flag,从zabbix数据库item和graph的对应表查询item是否具有对应的graph,如果有则传递1到脚本,无传递0
        eventid = sys.argv[3]          #脚本传递的第三个参数 告警信息的Event ID,用来命名png图片
    get_item_graph(itemid,flag,eventid)
  • 第二个Python实现连接企业微信API图文发送消息,此脚本中为调用卡片消息发送函数,我在实现分级发送时,采用了两个脚本,在Zabbix中判断告警级别使用不同脚本进行发送。
#!/usr/local/bin/python
#_*_coding:utf-8 _*_
import requests,sys,json
import urllib3
urllib3.disable_warnings()
reload(sys)
sys.setdefaultencoding('utf-8')

#获取Token
def GetToken(Corpid,Secret):
    Url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken"
    Data = {
        "corpid": Corpid,
        "corpsecret": Secret
    }
    r = requests.get(url=Url,params=Data,verify=False)
    Token = r.json()['access_token']
    return Token

#将获取到的趋势图,上传至企业微信临时素材,返回MediaId发送图文消息是使用
def GetImageUrl(Token,Path):
    Url = "https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token=%s&type=image" % Token
    data = {
        "media": open(Path,'r')
        }
    r = requests.post(url=Url,files=data)
    dict = r.json()
    return dict['media_id']

#卡片消息    
def SendCardMessage(Token,User,Agentid,Subject,Content):
    Url = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=%s" % Token
    Data = {
        "touser": User,                                 # 企业号中的用户帐号
        "msgtype": "textcard",                          # 消息类型
        "agentid": Agentid,                             # 企业号中的应用id
        "textcard": {
            "title": Subject,
            "description": Content,
            "url": "http://127.0.0.1/zabbix/",          #点击详情后打开的页面
            "btntxt": "详情"
        },
    "safe": "0"
    }
    r = requests.post(url=Url,data=json.dumps(Data),verify=False)
    return r.text

#图文消息
def SendnewsMessage(Token,User,Agentid,Subject,Content,Image,Itemid):
    Url = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=%s" % Token
    UUrl = "http://127.0.0.1/zabbix/history.php?action=showgraph&fullscreen=1&itemids[]="+Itemid
    Data = {
            "touser": User,                                 # 企业号中的用户帐号
            "msgtype": "mpnews",                            # 消息类型
            "agentid": Agentid,                             # 企业号中的应用id
            "mpnews": {
                    "articles": [
                    {
                            "title": Subject,
                            "thumb_media_id": Image,
                            "content": Content,
                            "content_source_url": UUrl,      #点击阅读原文后,打开趋势图大图,第一次需要登录
                            "digest": Content
                    }
                    ]
            },
            "safe": "0"
    }
    headers = {'content-type': 'application/json'}
    data = json.dumps(Data,ensure_ascii=False).encode('utf-8')
    r = requests.post(url=Url,headers=headers,data=data)
    return r.text

if __name__ == '__main__':
    User = sys.argv[1]                                                            
    Subject = sys.argv[2]                                                       
    Content = sys.argv[3]                                                       
    Path = sys.argv[4]                                                    
    Itemid = sys.argv[5]
    Corpid = "xxxxxxxxxxx"                                    # CorpID是企业号的标识
    Secret = "xxxxxxxxx"                                      # Secret是管理组凭证密钥
    Agentid = "100000x"                                       # 应用ID
    Token = GetToken(Corpid, Secret)
    Image = GetImageUrl(Token,Path) 
    SendnewsMessage(Token,User,Agentid,Subject,Content,Image,Itemid)
  • 第三步,将zabbix数据库中graphs_items表的信息拉去到一个文件中,我们可以通过读取该文件获取对应Item的GraphID号,从而进行抓取趋势图。(也可以直接去库中查询,但是这个表除非有新的监控项一般不会变化,所以我这里将表拉去到文件中,通过在文件中对比减少库查询的压力,将拉取动作每天执行一次即可)

    [root@zabbix ~]# 
    1 1 * * *  /usr/bin/mysql -h127.0.0.1 -uzabbix -pPASSWD -e "select graphid,itemid from zabbix.graphs_items" > /tmp/zabbix.txt
    
  • 第三个脚本,接收Zabbix传递的参数,并且过滤出ItemID,判断是有具有Graph并获取其ID,调用前两个脚本并且传递对应参数

#!/bin/bash
# name:wechat.sh

send_to=$1
subject=$2
message=$3

#获取itemid,eventid,PROBLEM或OK状态以命名PNG趋势图
#这块几个grep的格式需要特别注意,需要和zabbix发送过来的message格式相同
itemid=`echo $message | egrep -o "item ID: [0-9]*"| awk '{print $NF}'`
eventid=`echo $message | egrep -o "event ID: [0-9]*"| awk '{print $NF}'`
stat=`echo $message | egrep -o "Trigger status: PROBLEM|Trigger status: OK"| awk '{print $NF}'`
image=/tmp/$eventid"_"$stat".png"
#获取graphid和flag
graphid=`/bin/cat /tmp/zabbix.txt | awk '{ if($2=="'"$itemid"'"){print $1}}'`
if [ ! $graphid ]
then
    flag=0
else
    flag=1
fi

#在zabbix自动执行该脚本时,该脚本调用两个PY脚本,不太清楚原因,直接写脚本绝对路径无法执行,使用
解释器后跟脚本绝对路径也无法执行,但是尝试cd到目录后执行确可以,很蛋疼
cd /usr/local/zabbix/share/zabbix/alertscripts/
#使用image.py生成/tmp/$eventid"_"$stat".png图片后传递给wechat.py才有意义
./image.py "$itemid" "$flag" "$image"
./wechat.py "$send_to" "$subject" "$message" "$image" "$itemid"
#log
echo $image >> /tmp/zabbix_event.log
  • 到上面结束后,我们可以配置Zabbix之后就可以正常发送微信消息了,但是/tmp下生成的PNG图片还没有处理,上面以EVENT_ID+问题状态(PROBLEM|OK)来创建的文件,我们可以利用这些文件完成我的第三个需求
#!/bin/bash
# 定时任务脚本
# 根据生成的PNG检查时段内未处理的问题,并删除已处理的PNG

cat /tmp/zabbix_event.log | awk -F "_" '{print $1}' | sort | uniq -c | awk '{if($1%2==0){print $2}}' > /tmp/zabbix_rm.log
event=`cat /tmp/zabbix_rm.log`
for i in $event
do
    sed -i '/[$i]/d' /tmp/zabbix_event.log
    rm -rf $i*
done

cat /tmp/zabbix_event.log | awk -F "_" '{print $1}' | awk -F "/" '{print $NF}' > /tmp/zabbix_problem.log
#最后生成的/tmp/zabbix_problem.log中,保存了目前所有PROBLEM的EVENT_ID,将此ID通过第二个脚本提供的方式再发发送消息给微信即可。
#将此脚本添加到Crontab任务定时执行

Zabbix配置简述(脚本放置文件夹为zabbix配置参数AlertScriptsPath定义)

  • 新增报警媒介调用第三个脚本,wechat.sh
调用第三个脚本,wechat.sh
  • 新增用户,调用上述报警媒介,用户名为需要接收消息人的企业微信用户名
新增用户调用新增的报警媒介
  • 配置动作,使用新增方式发送消息。动作的消息中需要注意以下三个参数的格式,在wechat.sh中需要精确匹配后提取相关信息。别切需要以html编码格式进行换行,否则发送后无换行动作看着很乱。

  • 问题动作和恢复动作都需要发送信息,以下三个内容要相同

    Trigger status: {TRIGGER.STATUS}
    item ID: {ITEM.ID}
    event ID: {EVENT.ID}
    
告警动作
恢复动作
  • 具体告警信息

    <p>1、Trigger status: {TRIGGER.STATUS}</p>
    <p>2、Trigger severity: {TRIGGER.SEVERITY}</p>
    <p>3、{EVENT.DATE}--{EVENT.TIME}</p>
    <p>4、{ITEM.NAME1}--{ITEM.VALUE1}</p>
    <p>5、Original item ID: {ITEM.ID}</p>
    <p>6、Original event ID: {EVENT.ID}</p>
    

效果展示

图文消息
图文消息

点进去之后


点进去之后

点阅读全文,第一次需要登录,之后打开其他面板的阅读全都都不需要输入密码啦

阅读全文
卡片消息

是不是看着很清爽,低等级的告警,点详情后会跳转到zabbix主页面,卡片上一共可以显示八行消息,可以将需要的信息定义在前八行就可以了

卡片消息
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容