文档章节

zabbix短信报警统计以及报表展示

o翡翠谷o
 o翡翠谷o
发布于 06/22 18:14
字数 1598
阅读 555
收藏 6

一、需求

由于我们的业务报警比较频繁,之前是针对每个报警进行具体处理,但是有时还会重复出现,或者后续处理有时忘记跟进等,因此进行报警短信的统计,可以针对一些问题与业务跟进,明确后续的优化方向等。

二、实现

实现原理如下图:

zabbix_stats

其中核心部分zbx_statis,其实就是我编写的一个python脚本,它会从zabbixDB中查询过去一周的所有报警信息,并按不同维度统计每周的报表上传到公司的git上,同时将一条汇总的sql插入到cmdb的库表中展示。

三、报警格式依赖

报表的分析统计可以分两个维度:

  1. 报警类型纬度;
  2. 业务纬度;

不管从哪个维度进行的统计,都需要一个前提:报警格式规范化

针对报警内容的需求,我们对zabbix的trigger名称、主机名hostname等进行了规范化。

举例:

[17][15:31:04][productname-test-mysql-00][PROBLEM][005][cpu idle too low (<30%)][0.10 %][负责人:张学岩][15:31:07]

  • productname-test-mysql-00 是主机名,按业务等级进行命名,用于报警统计的业务纬度统计;
  • cpu idle too low (<30%) 是报警的类型,可以据此项进行类型纬度的统计;

通过维护一个主要业务列表,然后根据hostname匹配可以从业务纬度进行统计; 通过将报警类型规范化,用固定的格式放在报警信息的固定位置,可以按类型进行统计。

四、报表展示

以下是截取的部分报表的展示。

按报警类型纬度:

zabbix_stat_type

  • 最下面的详细信息跳转即业务纬度的统计。

按业务纬度:

zabbix_stat_product

CMDB统计图表:

zabbix_stat_cmdb

  • 很直观的展示每周的报警数量,如果优化比较好的话,会看到整体应该是下降的趋势。

五、附件

上文提到的报警统计 python 脚本,写的时间比较久了,现在看内容还是比较杂乱,我也懒得改了,放出来供大家参考,内容如下:

#!/usr/bin/env python26
# encoding: utf-8

import MySQLdb
import traceback
import copy
import datetime
import time
import operator

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

HOST = 'zabbix_db_host'
DB = 'zabbix'
PORT = 3306

RETRY_TIMES = 3

# 业务类型
GROUP_TYPE = ['A',
              'B',
              'C',
              '...',
              'X',
              'Y',
            ]

BASE_DIR = 'alerts_statistic/'

START_TIME = (datetime.datetime.now() - datetime.timedelta(days=(7 + datetime.datetime.now().weekday()))).strftime("%Y%m%d")
END_TIME = (datetime.datetime.now() - datetime.timedelta(days=(datetime.datetime.now().weekday()))).strftime("%Y%m%d")
DAY_SUM = 0
NIGHT_SUM = 0

class Connection:

    def __init__(self, *args, **kwargs):
        self.args = args
        self.kwargs = kwargs
        self.kwargs['user'] = "user"
        self.kwargs['passwd'] = "password"
        self.kwargs['port'] = kwargs['port'] if kwargs.has_key("port") else 3306
        self.kwargs['db'] = kwargs['db'] if kwargs.has_key("db") else "information_schema"
        self.kwargs['connect_timeout'] = 1

    def get_connection(self):
        ret = {"errno":0, 'errmsg':"", 'value':None}
        conn = None

        try:
            for i in range(0, RETRY_TIMES):
                conn = MySQLdb.connect(*self.args, **self.kwargs)
                if conn:
                    break

            ret['value'] = conn
        except Exception, err:
            ret['error'] = -1
            ret['errmsg'] = self.kwargs['host'] + str(err)
            traceback.print_exc()
        finally:
            return ret

def create_connection(*args, **kwargs):
    __conn__ = Connection(*args, **kwargs)
    ret = __conn__.get_connection()

    if ret['errno']:
        return None
    else:
        return ret['value']

def get_alert():

    start_timestamp = int(time.mktime(datetime.datetime.strptime(START_TIME + ' 00:00:00', "%Y%m%d %H:%M:%S").timetuple()))
    end_timestamp = int(time.mktime(datetime.datetime.strptime(END_TIME + ' 00:00:00', "%Y%m%d %H:%M:%S").timetuple()))

    try:
        conn = create_connection(host = HOST, db = DB, port = PORT, charset = 'utf8')

        if conn:
            SQL = """select from_unixtime(a.clock),a.subject
                        from alerts a,events b left join triggers c on b.objectid=c.triggerid
                        where a.eventid=b.eventid and a.alerttype=0 and a.subject not like '%test-%' and a.subject not like '%-test%'
                        and a.clock>={start_time} and a.clock<{end_time} group by a.subject order by a.clock"""
            SQL = SQL.format(start_time=start_timestamp, end_time=end_timestamp)
            print SQL
            cursor = conn.cursor()
            cursor.execute(SQL)
            ret = cursor.fetchall()
            cursor.close()
            conn.close()

            return ret
    except Exception,e:
        pass

def alert_statistic(alert_list):
    result = {}
    alerts_list = []
    if alert_list:
        for alert in alert_list:
            alerts_list.append(alert)
        for group in GROUP_TYPE:
            alerts = []
            alerts_list2 = copy.copy(alerts_list)
            for alert in alerts_list2:
                if group in alert[1]:
                    alerts.append(alert)
                    alerts_list.remove(alert)
            result[group] = alerts
        result['other'] = alerts_list
        result['status'] = 0
    else:
        result['status'] = 1
    return result

def write_to_file(result, day):
    if result:
        #statis_date = datetime.datetime.now().strftime("%Y-%m-%d")
        file_name = BASE_DIR + 'detail/' + START_TIME + '-' + END_TIME + '_' + day + '.md'
        writer = open(file_name,'w')
        writer.write('## ' + START_TIME + ' - ' + END_TIME + ': ' + day)
        alert_sum = 0
        for group in result.keys():
            alert_sum = alert_sum + len(result[group])
        writer.write('\n\n**短信总数:' + str(alert_sum) + '**')
        for group in result.keys():
            #print group, ":", len(result[group])
            if group == 'status':
                continue
            if len(result[group]) == 0:
                continue
            writer.write('\n\n### ' + group + '(' + str(len(result[group])) + ')' + '\n\n')
            writer.write('|报警内容|报警时间|\n|---|---|\n')
            for alert in result[group]:
                writer.write('|' + str(alert[1]) + '|' + str(alert[0]) + '|\n')
        writer.close()

def day_night_split(result, day='light'):
    results = {}
    if result:
        for group in result.keys():
            if group == 'status':
                continue
            alerts = result[group]
            alerts2 = copy.copy(alerts)
            for alert in alerts:
                alert_time = alert[0]
                alert_hour_time = alert_time.strftime("%H")
                if int(alert_hour_time) >= 7 and day == 'light':
                    pass
                elif int(alert_hour_time) >= 7 and day == 'night':
                    alerts2.remove(alert)
                elif int(alert_hour_time) < 7 and day == 'light':
                    alerts2.remove(alert)
                elif int(alert_hour_time) < 7 and day == 'night':
                    pass
            results[group] = alerts2
        return results

def alert_groupby(alert_list):
    alerts = []
    alert_group = []
    group_list = []
    for group in alert_list.keys():
        if group == 'status':
            continue
        for alert in alert_list[group]:
            alerts.append(alert[1])
    for alert in alerts:
        ### 兼容添加trigger id的改动
        temp1 = alert.split('][')
        alert_type = ''
        if len(temp1) == 9:
            alert_type = alert.split('][')[5].split(',')[0]
        else:
            alert_type = alert.split('][')[4].split(',')[0]
        if alert_type not in alert_group:
            alert_group.append(alert_type)
    for type in alert_group:
        type_dict = {}
        count = 0
        hostlist = []
        for alert in alerts:
            if type == alert.split('][')[4].split(',')[0] or type == alert.split('][')[5].split(',')[0]:
                count = count + 1
                hostname = alert.split('][')[2]
                if hostname not in hostlist:
                    hostlist.append(hostname)
        type_dict['type'] = type
        type_dict['hostlist'] = ",".join(hostlist)
        type_dict['count'] = str(count)
        group_list.append(type_dict)
    group_list.sort(key=lambda x : int(x['count']), reverse=True)
    return group_list

def write_group(group_light, group_night):
    if group_light and group_night:
        file_name = BASE_DIR + START_TIME + '-' + END_TIME + '.md'
        file_detail_light = START_TIME + '-' + END_TIME + '_白天' + '.md'
        file_detail_night = START_TIME + '-' + END_TIME + '_夜间' + '.md'
        writer = open(file_name,'w')
        writer.write('## ' + START_TIME + '-' + END_TIME + '\n\n')

        ## light
        alert_sum = 0
        for group in group_light:
            alert_sum = alert_sum + int(group['count'])
        global DAY_SUM
        DAY_SUM = alert_sum
        writer.write('### ' + '白天:' + str(alert_sum) + '\n\n')
        writer.write("|报警类型|报警数量|报警主机|\n|---|---|---|\n")
        for group in group_light:
            writer.write("|" + group['type'] + "|" + group['count'] + "|" + group['hostlist'] + "|\n")
        writer.write("\n[详细报警信息](detail/" + file_detail_light + ")\n\n")

        ## night
        alert_sum = 0
        for group in group_night:
            alert_sum = alert_sum + int(group['count'])
        global NIGHT_SUM
        NIGHT_SUM = alert_sum
        writer.write('### ' + '夜间:' + str(alert_sum) + '\n\n')
        writer.write("|报警类型|报警数量|报警主机|\n|---|---|---|\n")
        for group in group_night:
            writer.write("|" + group['type'] + "|" + group['count'] + "|" + group['hostlist'] + "|\n")
        writer.write("\n[详细报警信息](detail/" + file_detail_night + ")\n\n")

        writer.close()


def write_trend(sql):
    host = 'cmdb_host'
    db = 'cmdb_db'
    port = 3306
    try:
        conn = create_connection(host = host, db = db, port = port, charset = 'utf8')
        if conn:
            SQL = sql
            # SQL = SQL.format(start_time=start_timestamp, end_time=end_timestamp)
            print SQL
            cursor = conn.cursor()
            cursor.execute(SQL)
            ret = cursor.fetchall()
            cursor.close()
            conn.commit()
            conn.close()
            return ret
    except Exception,e:
        print e


def git_push():
    import os
    os.system("cd alerts_statis && git add alerts_statis && git commit -m 'update' && git push")

if __name__ == '__main__':
    # alert 列表
    alert_list = get_alert()
    # 按业务进行统计
    result = alert_statistic(alert_list)
    if result['status'] == 0:
        # 区分白天夜间
        result_day = day_night_split(result, 'light')
        result_night = day_night_split(result, 'night')
        # 按报警类型划分
        light_alert = alert_groupby(result_day)
        night_alert = alert_groupby(result_night)
        # 写入文件
        write_group(light_alert, night_alert)
        write_to_file(result_day, '白天')
        write_to_file(result_night, '夜间')
        git_push()
        sql = 'insert into alerts (start_time,end_time,all_count,day_count,night_count)values("' + START_TIME + '","' + END_TIME + '",' + str(DAY_SUM + NIGHT_SUM) + ',' + str(DAY_SUM) + ',' + str(NIGHT_SUM) + ');'
        # 写入cmdb
        write_trend(sql)
    else:
        print('There\'s no alert warning or something error.')

© 著作权归作者所有

共有 人打赏支持
o翡翠谷o
粉丝 15
博文 7
码字总数 9513
作品 0
海淀
数据库管理员
私信 提问
加载中

评论(6)

o翡翠谷o
o翡翠谷o

引用来自“林林未”的评论

你cmdb 用哪个?
cmdb是同事自己写的平台
林林未
林林未
你cmdb 用哪个?
o翡翠谷o
o翡翠谷o

引用来自“liuts”的评论

开头的 中括号 的17是什么意思呢
那个是zabbix的action id,跟我这个功能没啥关系了
liuts
liuts
开头的 中括号 的17是什么意思呢
liuts
liuts
开头的[ .17]
liuts
liuts
[17][15:31:04][productname-test-mysql-00][PROBLEM][005][cpu idle too low (<30%)][0.10 %][负责人:张学岩][15:31:07]
请问,开头的[17]表示什么意思呢
zabbix短信报警信息统计以及报表展示

需求 由于我们的业务报警比较频繁,之前是针对每个报警进行具体处理,但是有时还会重复出现,或者后续处理有时忘记跟进等,因此进行报警短信的统计,可以针对一些问题与业务跟进,明确后续的...

Linux就该这么学
09/29
0
0
分布式监控系统Zabbix-3.0.3--短信报警设置

前面已分别介绍了zabbix的邮件、微信报警设置,这些都是手机在有网络时才能收到报警信息,那如果手机没有网的情况下怎么办,这就需要考虑使用短信接口报警了。当服务出现故障达到预警级别是通...

吞吞吐吐的
2017/11/09
0
0
zabbix3.0.4 邮件告警详细配置

sendEmail是一个轻量级,命令行的SMTP邮件客户端。如果你需要使用命令行发送邮件,那么sendEmail是非常完美的选择:使用简单并且功能强大.这个被设计用在php、bash perl和web站点使用。 1.下载...

Keep_Smile_
2017/07/10
0
0
python写的zabbix短信报警程序,收不到短信

问题:用python写了一个短信的程序,在“报警媒介类型”中也调用了,设置了用户和动作。在报表--动作日志中也有记录。但是就是没有收到短信,而且短信程序的日志里面也没有。 解决办法:后来...

sailikung
01/10
0
0
运维必知必会的监控知识体系全梳理总结

监控是整个运维乃至整个产品生命周期中最重要的一环,事前及时预警发现故障,事后提供详实的数据用于追查定位问题。 目前业界有很多不错的开源产品可供选择。选择一款开源的监控系统,是一个...

English0523
2017/09/06
0
0

没有更多内容

加载失败,请刷新页面

加载更多

day149-2018-11-16-英语流利阅读-待学习

抖音登陆海外市场,歪果仁作何反应? Lala 2018-11-16 1.今日导读 抖音在国内已经火了有一段时间了,但你知道它已经进军海外,而且火了一把吗?中国版抖音的宣传语是“记录美好生活”,但外国...

飞鱼说编程
26分钟前
3
0
Confluence 6 教程:在 Confluence 中导航

当你对 Confluence 有所了解后,你会发现 Confluence 使用起来非常简单。这个教程主要是针对你使用的 Confluence 界面进行一些说明,同时向你展示在那里可以进行一些通用的任务和操作。 空间...

honeymose
今天
2
0
sed, awk 练习

1. sed打印某行到某行之间的内容 2. sed 转换大小写 将单词首字母转化大写 将所有小写转化大写 3. sed 在某一行最后面添加一个数字 4. 删除某行到最后一行 解析: {:a;N;$!ba;d} :a : 是...

Fc丶
今天
2
0
babel6升级到7,jest-babel报错:Requires Babel "^7.0.0-0", but was loaded with "6.26.3".

自从将前端环境更新到babel7,jest-babel之前是基于babel6的,执行时候就会报:Requires Babel "^7.0.0-0", but was loaded with "6.26.3". 很烦,因为连续帮好几台电脑修复这个问题,所以记...

曾建凯
今天
1
0
探索802.11ax

802.11ax承诺在真实条件下改善峰值性能和最差情况。 如何改善今天的Wi-Fi? 在决定如何改进当前版本以外的Wi-Fi时,802.11ac,IEEE和Wi-Fi联盟调查了Wi-Fi部署和行为,以确定更广泛使用的障碍...

linuxprobe16
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部