当前位置 博文首页 > 使用Python对Syslog信息进行分析并绘图的实现

    使用Python对Syslog信息进行分析并绘图的实现

    作者:格洛米爱学习 时间:2021-07-03 18:37

    实验目的:

    • 对设备Syslong信息进行分析记录,并写入sqlite数据库中;后续读取数据库的信息,对Syslog的严重级别分布、来源进行分析进行分析。
    • 同时监控OSPF的状态信息,状态一旦改变,进行告警。

    实验结果:

    监控Syslog的严重级别分布,和日志源分布,并绘图:

    在这里插入图片描述

    在这里插入图片描述

    监控OSPF状态信息:

    在这里插入图片描述

    实验环境:

    两台CSR1000v,完成Syslog(其中一台)和OSPF的配置:

    logging hosy x.x.x.x /将Syslong日志信息发送给目的主机(运行python)进行处理。

    logging trap debugging /监控所有级别的Syslog信息。

    ospf配置略。

     python脚本:

    脚本一:监控CSR1000v发送的Syslog Trap信息,并对信息进行分词处理,写入数据库。同时监控OSPF邻居状态是否改变。

    import socketserver
    import re
    from dateutil import parser
    import os
    import sqlite3
    
    # facility与ID的对应关系的字典,方便后续分词时提取对应的信息
    facility_dict = {0: 'KERN',
                     1: 'USER',
                     2: 'MAIL',
                     3: 'DAEMON',
                     4: 'AUTH',
                     5: 'SYSLOG',
                     6: 'LPR',
                     7: 'NEWS',
                     8: 'UUCP',
                     9: 'CRON',
                     10: 'AUTHPRIV',
                     11: 'FTP',
                     16: 'LOCAL0',
                     17: 'LOCAL1',
                     18: 'LOCAL2',
                     19: 'LOCAL3',
                     20: 'LOCAL4',
                     21: 'LOCAL5',
                     22: 'LOCAL6',
                     23: 'LOCAL7'}
    
    # severity_level与ID的对应关系的字典,方便后续分词时提取对应的信息
    severity_level_dict = {0: 'EMERG',
                           1: 'ALERT',
                           2: 'CRIT',
                           3: 'ERR',
                           4: 'WARNING',
                           5: 'NOTICE',
                           6: 'INFO',
                           7: 'DEBUG'}
    
    # 分词处理的类
    class SyslogUDPHandler(socketserver.BaseRequestHandler):
        def handle(self):
            data = bytes.decode(self.request[0].strip())  # 读取数据
            # print(data)
            syslog_info_dict = {'device_ip': self.client_address[0]}
            try:
                # syslog信息如下:<187>83: *Apr  4 00:03:12.969: %LINK-3-UPDOWN: Interface GigabitEthernet2, 
                # changed state to up,我们需要对此进行提炼分词,并将分词结果记入到一个字典里面;具体的分词过程简单了解即可
                syslog_info = re.match(r'^<(\d*)>(\d*): \*(.*): %(\w+)-(\d)-(\w+): (.*)', str(data)).groups()
                # print(syslog_info[0]) 提取为整数 例如 185
                # 185 二进制为 1011 1001
                # 前5位为facility  >> 3 获取前5位
                # 后3位为severity_level  & 0b111 获取后3位
                syslog_info_dict['facility'] = (int(syslog_info[0]) >> 3)
                syslog_info_dict['facility_name'] = facility_dict[int(syslog_info[0]) >> 3]
                syslog_info_dict['logid'] = int(syslog_info[1])
                syslog_info_dict['time'] = parser.parse(syslog_info[2])
                syslog_info_dict['log_source'] = syslog_info[3]
                syslog_info_dict['severity_level'] = int(syslog_info[4])
                syslog_info_dict['severity_level_name'] = severity_level_dict[int(syslog_info[4])]
                syslog_info_dict['description'] = syslog_info[5]
                syslog_info_dict['text'] = syslog_info[6]
            except AttributeError:
                # 有些日志会缺失%SYS-5-CONFIG_I, 造成第一个正则表达式无法匹配 , 也无法提取severity_level
                # 下面的icmp的debug就是示例
                # <191>91: *Apr  4 00:12:29.616: ICMP: echo reply rcvd, src 10.1.1.80, dst 10.1.1.253, topology BASE, dscp 0 topoid 0
                syslog_info = re.match(r'^<(\d*)>(\d*): \*(.*): (\w+): (.*)', str(data)).groups()
                print(syslog_info[0])
                syslog_info_dict['facility'] = (int(syslog_info[0]) >> 3)
                syslog_info_dict['facility_name'] = facility_dict[int(syslog_info[0]) >> 3]
                syslog_info_dict['logid'] = int(syslog_info[1])
                syslog_info_dict['time'] = parser.parse(syslog_info[2])
                syslog_info_dict['log_source'] = syslog_info[3]
                # 如果在文本部分解析不了severity_level, 切换到syslog_info[0]去获取
                # 185 二进制为 1011 1001
                # 前5位为facility  >> 3 获取前5位
                # 后3位为severity_level  & 0b111 获取后3位
                syslog_info_dict['severity_level'] = (int(syslog_info[0]) & 0b111)
                syslog_info_dict['severity_level_name'] = severity_level_dict[(int(syslog_info[0]) & 0b111)]
                syslog_info_dict['description'] = 'N/A'
                syslog_info_dict['text'] = syslog_info[4]
            # print(syslog_info_dict)
            # 根据分词后的字典进行分析,如果用正则表达式匹配到了OSPF状态有了改变,则打印告警信息
            if syslog_info_dict['log_source'] == 'OSPF':
                result_ospf = re.findall('(Process \d+), Nbr ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}).+to (\w+)', syslog_info_dict['text'])[0]
                if result_ospf:
                    print('OSPF '+result_ospf[0]+' Neighbor '+result_ospf[1]+' status '+result_ospf[2])
            # 将字典信息写入sqlite数据库中
            conn = sqlite3.connect(gl_dbname)
            cursor = conn.cursor()
            cursor.execute("insert into syslogdb (time, \
                                                  device_ip, \
                                                  facility, \
                                                  facility_name, \
                                                  severity_level, \
                                                  severity_level_name, \
                                                  logid, \
                                                  log_source, \
                                                  description, \
                                                  text) values ('%s', '%s', %d, '%s', %d, '%s', %d, '%s', '%s', '%s')" % (
            syslog_info_dict['time'].strftime("%Y-%m-%d %H:%M:%S"),
            syslog_info_dict['device_ip'],
            syslog_info_dict['facility'],
            syslog_info_dict['facility_name'],
            syslog_info_dict['severity_level'],
            syslog_info_dict['severity_level_name'],
            syslog_info_dict['logid'],
            syslog_info_dict['log_source'],
            syslog_info_dict['description'],
            syslog_info_dict['text'],
            ))
            conn.commit()
    
    
    if __name__ == "__main__":
        # 使用Linux解释器 & WIN解释器
        global gl_dbname
        gl_dbname = 'syslog.sqlite'
        if os.path.exists(gl_dbname):
            os.remove(gl_dbname)
        # 连接数据库
        conn = sqlite3.connect(gl_dbname)
        cursor = conn.cursor()
        # 创建数据库
    
        cursor.execute("create table syslogdb(id INTEGER PRIMARY KEY AUTOINCREMENT,\
                                             time varchar(64), \
                                             device_ip varchar(32),\
                                             facility int,\
                                             facility_name varchar(32),\
                                             severity_level int,\
                                             severity_level_name varchar(32),\
                                             logid int,\
                                             log_source varchar(32), \
                                             description varchar(128), \
                                             text varchar(1024)\
                                             )")
        conn.commit()
        try:
            HOST, PORT = "0.0.0.0", 514  # 本地地址与端口
            server = socketserver.UDPServer((HOST, PORT), SyslogUDPHandler)  # 绑定本地地址,端口和syslog处理方法
            print("Syslog 服务已启用, 写入日志到数据库!!!")
            server.serve_forever(poll_interval=0.5)  # 运行服务器,和轮询间隔
    
        except (IOError, SystemExit):
            raise
        except KeyboardInterrupt:  # 捕获Ctrl+C,打印信息并退出
            print("Crtl+C Pressed. Shutting down.")
        finally:
            conn.commit()
    
    

    脚本二:读取数据库中的信息,并根据信息进行饼图绘制。

    import sqlite3
    from matplotlib import pyplot as plt
    from syslog_server_to_db import severity_level_dict
    
    # 绘制严重等级的饼图
    def syslog_show_error_level_pie(dbname):
        # 连接数据库
        conn = sqlite3.connect(dbname)
        cursor = conn.cursor()
        # 提取安全级别和数量信息
        cursor.execute("select severity_level as level,COUNT(*) as count from syslogdb group by severity_level")
        yourresults = cursor.fetchall()
    
        level_list = []
        count_list = []
    
        # 把结果写入leve_list和count_list的列表
        for level_info in yourresults:
            level_list.append(severity_level_dict[level_info[0]])
            count_list.append(level_info[1])
    
        print(level_list)
        print([float(count) for count in count_list])
    
        plt.rcParams['font.sans-serif'] = ['SimHei']  # 设置中文
        # 调节图形大小,宽,高
        plt.figure(figsize=(6, 6))
    
        # 使用count_list的比例来绘制饼图
        # 使用level_list作为注释
        patches, l_text, p_text = plt.pie(count_list,
                                          labels=level_list,
                                          labeldistance=1.1,
                                          autopct='%3.1f%%',
                                          shadow=False,
                                          startangle=90,
                                          pctdistance=0.6)
    
        # 改变文本的大小
        # 方法是把每一个text遍历。调用set_size方法设置它的属性
        for t in l_text:
            t.set_size = 30
        for t in p_text:
            t.set_size = 20
        # 设置x,y轴刻度一致,这样饼图才能是圆的
        plt.axis('equal')
        plt.title('SYSLOG严重级别分布图')  # 主题
        plt.legend()
        plt.show()
    
    # 绘制Syslog来源的饼图
    def syslog_show_source_pie(dbname):
        # 连接数据库
        conn = sqlite3.connect(dbname)
        cursor = conn.cursor()
        # 提取log源与其对应的数量
        cursor.execute("select log_source,COUNT(*) as count from syslogdb group by log_source")
        yourresults = cursor.fetchall()
    
        source_list = []
        count_list = []
    
        # 将数据库的信息,依次写入两个列表
        for source_info in yourresults:
            source_list.append(source_info[0])
            count_list.append(source_info[1])
    
        print(source_list)
        print([float(count) for count in count_list])
    
        plt.rcParams['font.sans-serif'] = ['SimHei']  # 设置中文
        # 调节图形大小,宽,高
        plt.figure(figsize=(6, 6))
    
        # 使用count_list的比例来绘制饼图
        # 使用level_list作为注释
        patches, l_text, p_text = plt.pie(count_list,
                                          labels=source_list,
                                          labeldistance=1.1,
                                          autopct='%3.1f%%',
                                          shadow=False,
                                          startangle=90,
                                          pctdistance=0.6)
    
        # 改变文本的大小
        # 方法是把每一个text遍历。调用set_size方法设置它的属性
        for t in l_text:
            t.set_size = 30
        for t in p_text:
            t.set_size = 20
        # 设置x,y轴刻度一致,这样饼图才能是圆的
        plt.axis('equal')
        plt.title('日志源分布图')  # 主题
        plt.legend()
        plt.show()
    
    
    if __name__ == '__main__':
        syslog_show_error_level_pie("syslog.sqlite")
        syslog_show_source_pie("syslog.sqlite")
    
    

    参考资料来源:现任明教教主

    jsjbwy
    下一篇:没有了