一、日志解析
- 日志异常检测任务一般分为日志采集、日志解析、特征标识、异常判别4个步骤
- 日志先使用LogHub提供的系统日志数据集进行训练模型,方便测试模型是否正常运行。后期再使用在线日志进行模型训练
- 日志解析我选用的是Drain算法(depth tree based online log parsing),将日志解析成结构化数据。
二、Drain算法(文章链接)
- Drain算法是基于固定深度树的在线日志解析方法,它将原始日志消息以流的方式聚集到不同的日志组中。
- 这种解决方案非常慢,因为随着日志组的增加,解析时间增长的非常迅速。
- 每一个 logGroup 都由两个部分组成,log event 和 log IDS,而 log event 是描述一个logGroup的最佳模板。
- 解析树的一个特殊设计就是所有的叶子节点的深度都是相同的(取决于你预先设定的参数depth),这个参数会限制算法在搜索过程中访问到的叶子节点,但是会大幅度提升效率。
三、具体实现步骤(代码链接)
1. 预处理(Preprocess by Domain Knowledge)
预处理可以提高解析精度,Drain允许用户提供基于领域知识的简单正则表达式,这些正则表达式表示常用变量,例如IP地址和块ID。然后通过正则表达式从原始日志消息中删除匹配的标记。
预处理第一步:先生成正则表达式以拆分日志信息(以HDFS日志为例)
预处理第二步,将日志文件转换为数据帧
可将 Pandas 库视作 Python 表示和操作表格结构化数据的原生方法(Python化的处理方法)。 Pandas的关键结构是数据帧。可将数据帧视作关系型表的 Python 方法
预处理:在日志中移除token(IP,block_id等)
2. 搜索遍历解析树并更新解析树
class Node:
def __init__(self,childNode=None,depth=0,name=None):
# 一个节点包括子字节,当前节点的深度,和当前节点的名字/代号
if childNode is None:
childNode=dict()
self.childNode=childNode
self.depth=depth
self.name=name
class LogGroup:
def __init__(self,logTemplate="",logIDList=None):
# 一个日志集群包括日志模板和日志ID列表
if logIDList is None:
logIDList=[]
self.logTemplate=logTemplate
self.logIDList=logIDList
解析树的第一层是Length层,他们是日志消息长度不同的分组。日志消息长度,这里指的是一个日志消息里面 tokens 的个数。
这是基于以下假设,具有相同日志事件可能具有相同的日志消息长度。
有三种情况需要使用Add函数(添加新的长度节点或者是新的日志集群),标记matchGroup为None:
1、Length层没有该日志长度
2、Length层有该日志长度,但没有该token(第一个单词)
3、计算相似度时,simSeq<st,表示没有合适的日志组
有两种情况要匹配成特殊符号<*>
1、如果一个token包含数字,它会匹配一个 <*> 节点
2、如果一个节点已经有了maxchild 个子节点,那么任何没有被匹配的tokens都将会匹配为内部特殊符号 <*>
计算相似度的公式:
计算日志集群列表中每个集群模板与当前日志事件的相似度,用最大的进行比较,如果maxSimSeq<st,表示没有合适的日志组
3、dataframe导出到 csv文件
使用pandas.to_csv()函数即可