文章目录
前言
Log2seq是一个能够将原始的日志数据转化为word sequence的python开源工具包,如原始日志内容为:Jan 1 12:34:56 host-device1 system[12345]: host 2001:0db8:1234::1 (interface:eth0) disconnected
该工具包能够将日志中的每一项都给提取出来,如提取出时间、日期、产生日志的组件以及日志的内容等,其中对于日志的内容,它还可以将里面的内容进行切分,比如切分出IP地址等等,相当于对日志数据进行预处理,以便未来更好地进行日志分析。
项目github地址: Log2seq
一、预备
一条日志实际上包含两个部分,一个是Header,一个是Statement。前者是指示日志时间、日期、级别等信息的字段,如前言中的Jan 1 12:34:56 host-device1,后者则是指日志本身的content,如前言中的后半部分。与之相对的,Header一般结构很规律,而Statement则是没有规律的,不同的组件产生的Statement基本上是完全不同的。因此,Log2seq对两部分分开处理。虽然是分开处理,但会提供一个接口让使用者可以一步到位。在接下来讲述也将按照这样的逻辑顺序。
二、Header的处理
1.基本概念
在Header的处理中,由于其结构规律的特征,一般都是 “特征1 特征2。。”这样的结构,因此将这里面的特征称为Item,Item是一个抽象的类,我们都知道Item肯定有不同的类型,比如字符串类型或者时间日期的类型又或者int类型,因此抽象类引申出了能够提取不同内容的Item子类。
2.Header的使用
在这里最重要的类就是log2seq.header.HeaderParser
在进行日志异常检测的比赛中,有如下日志数据
10001 2021-05-21 15:47:36.440 378166 DEBUG oslo_concurrency.processutils [req-32fe6dfe-d5fe-47d9-b208-12232e73c90a - - - - -] Running cmd (subprocess): /usr/bin/python2 -m oslo_concurrency.prlimit --as=1073741824 --cpu=2 – env LC_ALL=C LANG=C qemu-img info /var/lib/nova/instances/3ad77c0d-f281-408d-8c08-ebd39514a014/disk execute /usr/lib/python2.7/site-packages/oslo_concurrency/processutils.py:344
对应意义分别是:LineId,Date,Time,Pid,Level,Component,ADDR,Content
要想把各项分别提取出来,用如下代码:
from log2seq import header
lineid_item = header.Digit('LineId')
date_item = header.UserItem(name='Date',pattern=r'\d{4}-\d{2}-\d{2}')
time_item = header.UserItem(name='Time',pattern=r'\d{2}:\d{2}:\d{2}\.\d{2,3}')
pid_item = header.Digit('PId')
level_item = header.UserItem(name='Level',pattern=r'[a-zA-Z]+')
component_item = header.UserItem(name='Component',pattern=r'[a-zA-Z_]+\.[a-zA-Z_]+')
addr_item = header.UserItem(name='ADDR',pattern=r'[a-zA-Z0-9\s-]+')
statement_item = header.Statement()
head_par = header.HeaderParser(items=[lineid_item,date_item,time_item,pid_item,level_item,component_item,addr_item,statement_item],
full_format=r'<0> <1> <2> <3> <4> <5> \[<6>\] <7>',reformat_timestamp=False)
line = '10001 2021-05-21 15:47:36.440 378166 DEBUG oslo_concurrency.processutils [req-32fe6dfe-d5fe-47d9-b208-12232e73c90a - - - - -] Running cmd (subprocess): /usr/bin/python2 -m oslo_concurrency.prlimit --as=1073741824 --cpu=2 -- env LC_ALL=C LANG=C qemu-img info /var/lib/nova/instances/3ad77c0d-f281-408d-8c08-ebd39514a014/disk execute /usr/lib/python2.7/site-packages/oslo_concurrency/processutils.py:344 \n'
result = head_par.process_line(line)
print(result)
---------------------
result:
{'LineId': 10001, 'Date': '2021-05-21', 'Time': '15:47:36.440', 'PId': 378166, 'Level': 'DEBUG', 'Component': 'oslo_concurrency.processutils', 'ADDR': 'req-32fe6dfe-d5fe-47d9-b208-12232e73c90a - - - - -', 'message': 'Running cmd (subprocess): /usr/bin/python2 -m oslo_concurrency.prlimit --as=1073741824 --cpu=2 -- env LC_ALL=C LANG=C qemu-img info /var/lib/nova/instances/3ad77c0d-f281-408d-8c08-ebd39514a014/disk execute /usr/lib/python2.7/site-packages/oslo_concurrency/processutils.py:344 '}
有几点需要记录:
1.date_item我没有用它提供的类log2seq.header.Date,这是因为用item.pattern后发现其正则不符合该日志的日期格式,所以用它的自定义item类了。time_item也是同理
三、Statement的处理
1.基本概念
Statement的处理是按照顺序进行的,即先进行这一项操作,再进行下一项操作,比如先通过空格进行分词,再给IP地址打标禁止其分割,再通过其他分隔符进行分词。这里面操作的单元叫做一个action。
该处使用的url网络请求的数据。
2.Statement的使用
还是上个日志数据,只用content的内容:
Running cmd (subprocess): /usr/bin/python2 -m oslo_concurrency.prlimit --as=1073741824 --cpu=2 – env LC_ALL=C LANG=C qemu-img info /var/lib/nova/instances/3ad77c0d-f281-408d-8c08-ebd39514a014/disk execute /usr/lib/python2.7/site-packages/oslo_concurrency/processutils.py:344
from log2seq import statement
parser = statement.StatementParser([statement.Split(" ")])
line = 'Running cmd (subprocess): /usr/bin/python2 -m oslo_concurrency.prlimit --as=1073741824 --cpu=2 -- env LC_ALL=C LANG=C qemu-img info /var/lib/nova/instances/3ad77c0d-f281-408d-8c08-ebd39514a014/disk execute /usr/lib/python2.7/site-packages/oslo_concurrency/processutils.py:344'
result = parser.process_line(line)
print(result)
-----------------------
(['Running', 'cmd', '(subprocess):', '/usr/bin/python2', '-m', 'oslo_concurrency.prlimit', '--as=1073741824', '--cpu=2', '--', 'env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'info', '/var/lib/nova/instances/3ad77c0d-f281-408d-8c08-ebd39514a014/disk', 'execute', '/usr/lib/python2.7/site-packages/oslo_concurrency/processutils.py:344'], ['', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ''])
三、同时进行header和statement的处理
Log2seq提供了log2seq.LogParser类供使用,为了将以上两个结合在一起,代码如下:
from log2seq import header
from log2seq import statement
import log2seq
line = '10001 2021-05-21 15:47:36.440 378166 DEBUG oslo_concurrency.processutils [req-32fe6dfe-d5fe-47d9-b208-12232e73c90a - - - - -] Running cmd (subprocess): /usr/bin/python2 -m oslo_concurrency.prlimit --as=1073741824 --cpu=2 -- env LC_ALL=C LANG=C qemu-img info /var/lib/nova/instances/3ad77c0d-f281-408d-8c08-ebd39514a014/disk execute /usr/lib/python2.7/site-packages/oslo_concurrency/processutils.py:344 \n'
lineid_item = header.Digit('LineId')
date_item = header.UserItem(name='Date',pattern=r'\d{4}-\d{2}-\d{2}')
time_item = header.UserItem(name='Time',pattern=r'\d{2}:\d{2}:\d{2}\.\d{2,3}')
pid_item = header.Digit('PId')
level_item = header.UserItem(name='Level',pattern=r'[a-zA-Z]+')
component_item = header.UserItem(name='Component',pattern=r'[a-zA-Z_]+\.[a-zA-Z_]+')
addr_item = header.UserItem(name='ADDR',pattern=r'[a-zA-Z0-9\s-]+')
statement_item = header.Statement()
header_par = header.HeaderParser(items=[lineid_item,date_item,time_item,pid_item,level_item,component_item,addr_item,statement_item],
full_format=r'<0> <1> <2> <3> <4> <5> \[<6>\] <7>',reformat_timestamp=False)
state_parser = statement.StatementParser([statement.Split(" ")])
par = log2seq.LogParser(header_par,state_parser)
result = par.process_line(line)
print(result)
----------------------------------
result:
{'LineId': 10001, 'Date': '2021-05-21', 'Time': '15:47:36.440', 'PId': 378166, 'Level': 'DEBUG', 'Component': 'oslo_concurrency.processutils', 'ADDR': 'req-32fe6dfe-d5fe-47d9-b208-12232e73c90a - - - - -', 'message': 'Running cmd (subprocess): /usr/bin/python2 -m oslo_concurrency.prlimit --as=1073741824 --cpu=2 -- env LC_ALL=C LANG=C qemu-img info /var/lib/nova/instances/3ad77c0d-f281-408d-8c08-ebd39514a014/disk execute /usr/lib/python2.7/site-packages/oslo_concurrency/processutils.py:344 ', 'words': ['Running', 'cmd', '(subprocess):', '/usr/bin/python2', '-m', 'oslo_concurrency.prlimit', '--as=1073741824', '--cpu=2', '--', 'env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'info', '/var/lib/nova/instances/3ad77c0d-f281-408d-8c08-ebd39514a014/disk', 'execute', '/usr/lib/python2.7/site-packages/oslo_concurrency/processutils.py:344'], 'symbols': ['', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']}
总结
log2seq感觉是个很适合做日志处理的库,可以按照自己的需求制作正则表达式然后进行item以及content内容的提取和分词,但是才7颗star,未来前途无量啊。本来我是准备把学习这个库的心得写出来的,想要把整个库讲明白,但是三分钟热度,坚持不下去了。而且也觉得在写的时候不知道该怎么表达,感觉还是官方文档讲的比较清楚,但是官方文档的例子太少了尤其是header的处理。所以建议后面的使用者还是要以官网文档为主,可以看看这篇博客的例子辅助理解,如果能起到抛砖引玉的效果,我会很欣慰的。by the way,这个库其实还是辅助做log parsing的,我们比赛的日志数据实在是太乱了,后面应该还会再更新一下日志预处理的博客来记录。