文档章节

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

o翡翠谷o
 o翡翠谷o
发布于 06/22 18:14
字数 1598
阅读 203
收藏 6
点赞 1
评论 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-3.0.3--短信报警设置

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

吞吞吐吐的
2017/11/09
0
0
运维必知必会的监控知识体系全梳理总结

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

English0523
2017/09/06
0
0
zabbix3.0.4 邮件告警详细配置

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

Keep_Smile_
2017/07/10
0
0
一篇文章全面了解监控知识体系

一篇文章全面了解监控知识体系 标签(空格分隔): 监控 zabbix 前言介绍 监控是整个运维乃至整个产品生命周期中最重要的一环,事前及时预警发现故障,事后提供详实的数据用于追查定位问题。...

Bgxuliangwei
2017/04/10
0
0
监控的平台与原理

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

枫晚
2017/04/22
0
0
python写的zabbix短信报警程序,收不到短信

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

sailikung
01/10
0
0
zabbix自定义脚本实现短信报警提醒

一 简介 通常,在zabbix的web界面配置好之后为了能够及时收到zabbix的报警信息,我们需要配置“报警媒介”来通知我们。其中常用的两种报警媒介分别是:Email和SMS,即:发邮件通知和发短信通...

pangfc
06/26
0
0
zabbix监控环境的搭建

zabbix是一个基于WEB界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案。 zabbix能监视各种网络参数,保证服务器系统的安全运营;并提供柔软的通知机制以让系统管理员快速定位...

宏强
2017/05/14
0
0
一个优雅的报警处理系统范例

做运维的同学都知道,运维一定离不开Zabbix、Nagios之类的监控软件。目前,类似的软件在监控和数据采集方面已经做到了极致,但是在报警处理上并没有很完美的解决方案,比如,经常出现高质量报...

superbigsea
2017/03/26
0
0
​利用腾讯企业邮箱zabbix3.x邮件告警详细配置(微信/QQ/短信通知)

实战利用腾讯企业邮箱zabbix3.x邮件(微信/QQ/短信)告警详细配置 对Linux有兴趣的朋友加入QQ群:476794643 在线交流 本文防盗链:http://zhang789.blog.51cto.com 声明 声明:本文参考了网上...

好笔记运维
2017/01/05
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

java 重写排序规则,用于代码层级排序

1.dataList 是个List<Map<String,Object>> 类型的数据,所以比较的时候是冲map中获取数据,并且数据不能为空。 2.dataList 类型是由自己定义的,new Comparator<Map<String,Object>> 也是对应......

轻量级赤影
7分钟前
0
0
分布式大型互联网企业架构!

摘要: 开发工具 1.Eclipse IDE:采用Maven项目管理,模块化。 2.代码生成:通过界面方式简单配置,自动生成相应代码,目前包括三种生成方式(增删改查):单表、一对多、树结构。生成后的代码...

明理萝
8分钟前
0
1
对MFC程序的一点逆向分析:定位按钮响应函数的办法

因为消息响应函数保存在AFX_MSGMAP_ENTRY数组中, 观察nMessage、nCode、nID、pfn利用IDA在rdata段中搜索即可, 在IDA中找到代码段基址0x401000,函数地址0x403140, 在WinDbg中运行!addre...

oready
8分钟前
0
0
阻抗匹配与史密斯(Smith)圆图基本原理

参考:http://bbs.eeworld.com.cn/thread-650695-1-1.html

whoisliang
13分钟前
0
0
maven配置文件分离

一、 简介 遇到很多次别人处理的项目,测试环境,本地开发和线上环境的配置不一样,每一次部署都要重新修改配置文件,提交审核代码,才能打包,非常不方便。 其实相信很多人都知道可以使用m...

trayvon
13分钟前
0
0
MacOS和Linux内核的区别

导读 有些人可能认为MacOS和Linux内核有相似之处,因为它们可以处理类似的命令和类似的软件。甚至有人认为苹果的MacOS是基于linux的。事实上,这两个内核的历史和特性是非常不同的。今天,我...

问题终结者
30分钟前
1
0
SpringBoot | 第八章:统一异常、数据校验处理

前言 在web应用中,请求处理时,出现异常是非常常见的。所以当应用出现各类异常时,进行异常的捕获或者二次处理(比如sql异常正常是不能外抛)是非常必要的,比如在开发对外api服务时,约定了响...

oKong
37分钟前
2
0
mysql高级

一、存储引擎 InnoDB MyISAM 比较 二、数据类型 整型 浮点数 字符串 时间和日期 三、索引 索引分类 索引的优点 索引优化 B-Tree 和 B+Tree 原理 四、查询性能优化 五、切分 垂直切分 水平切分...

丁典
58分钟前
1
0
rsync通过同步服务、系统日志、screen工具

rsync通过后台服务同步 在远程主机中建立一个rsync服务器,在服务器上配置好rsync的各种应用,然后将本机作为rsync的一个客户端连接远程的rsync服务器。 首先在A机器上建立并且配置rsync的配...

黄昏残影
今天
5
0
Spring Cloud Gateway 接口文档聚合实现

在微服务架构下,通常每个微服务都会使用Swagger来管理我们的接口文档,当微服务越来越多,接口查找管理无形中要浪费我们不少时间,毕竟懒是程序员的美德。 由于swagger2暂时不支持webflux 走...

冷冷gg
今天
150
2

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部