日志数据是一种半结构化的数据,它是由特定的代码生成的。其实可以理解为“print”语句。在我们进行print的时候,我们一般会包含常量和变量。日志的模板解析就是这个过程的倒推方式。由日志推出你的“print”语句。
日志解析是什么
如下图所示:
中间的log Message为日志数据,也就是日志文件系统中生成的数据。
上面的代码就是生成日志的语句,下面就是经过日志解析后得到的结构化数据,用于日志分析。
日志模板和参数
日志模板其实是我们print语句的中的常量和变量用特定符号(例如< * >)表示的组合。
例如LOG.info("Received block " + block + " of size " + block.getNumBytes() + " from " + inAddr)打印出的日志中,都会出现文本:Received block 、of size 、from,这些文本我们称为常量,而由于每次打印日志时系统状态的不同,每条日志打印出的block、block.getNumBytes()、inAddr可能不同,这些文本我们称为参数。我们将日志中的常量保留,参数用特定符号< * >代替,这样所生成的文本就是日志的模板。即下面的Received block < * > of size < * > from /< * >。
日志参数的就是变量的部分,也就是print传入的变量部分。也就是图中的PARAMETERS部分。
为什么要日志解析
在现在的计算机中,日志数量是非常庞大的,一个系统一天内可能就会产生上百万条日志,人眼直接观测显然不现实,但通过日志模式解析,我们可以将上百万条日志压缩成几百个模板,便于人眼观看,还有一部分原因是,便于作为计算机的输入。
目前解析比较好的Drain
用了树结构的方式对日志进行分组。Drain的分组策略有两块:根据日志的长度分组以及根据日志的前几个单词分组。Drain的树深度可设,树深度决定了用前多少个单词进行分组。其分组策略如图所示,当有一条日志需要解析时,会根据该日志的长度及前几个单词依次向下搜索,直到叶子节点。叶子节点下存储着该组别中的聚类簇,搜索到叶子节点后再计算相似度,根据相似度计算结果更新聚类中心或者创建新的聚类簇。
算法流程如下:
-
预处理,以分隔符/空格为单位将日志切分为一个个的token;
-
根据日志token长度去第二层(每个节点对应一个长度)寻找对应节点,比如Receive from node 4匹配的节点对应日志token长度为4;
-
根据日志token按顺序去进行分裂,这里受到depth限制,分裂树深为depth-2(去除root和length层);
-
分裂到叶子节点后,计算日志与各个模板的相似度simSeq,返回simSeq大于阈值st并且相似度最高的模板;
-
更新Parsetree,当日志在叶子节点匹配到了模板,并且部分token有差异,则用<*>替换;当没有匹配到模板时,则将新的日志加入到该叶子节点的模板列表,作为新的模版。
利用日志模板进行数据压缩
日志每天生成每天生成GB甚至TB即的数据,对其进行数据压缩,可有效的解决磁盘存储问题。
压缩思想
由于上面我们解释了,日志模板的作用为利用少数的模板表示大量的日志内容,基于这个思想我们将模板索引和参数组表达日志内容,将大量减少日志内容的存储。
日志内容
Receiving block blk_-1608999687919862906 src: /10.250.14.224:42420 dest: /10.250.14.224:50010
压缩后的日志为
1 [blk_-1608999687919862906,10.250.14.224:42420,10.250.14.224:50010]
模板索引内容
1 Receiving block <*> src: <*> dest: <*>
基于上面的思想我们可以节约很大一部内存空间,对数据进行高效的压缩。
测试结果
基于上面的思想 我们进行测是 对一个原始数据为2.81GB的数据进行压缩,压缩后的数据为1.27GB,并对其数据进行还原,没有数据丢失。