C++,python,热爱算法和机器学习
全部博文(1214)
分类: NOSQL
2018-01-05 18:19:42
今天遇到个比较奇葩的日志解析问题,我们的日志文件内容是标准的JSON格式的,但是在使用Logstash解析的时候,我们希望也能够保存原始的日志字符串到ES
|
|
我开始的想法是从track.log日志文件中读取日志信息,因为track.log日志是标准的JSON格式的,所以直接将codec设置成json,因为logs是一个内嵌的数组,然后在filter根据logs做split,会把logs的数组拆分出多条日志信息,然后在匹配指定格式的timestamp并生成新的字段@timestamp。
|
|
上述做法的确能够将track.log日志解析成功并且写入到ES中,但是没有办法获取到原日志信息,对我们来说是无法满足要求的。
为什么没办法获取到原日志信息呢?这里再次梳理下Logstash的处理流程。
原来一直以为是
应该补上decode/encode
decode/encode就是解码器和编码器
分析了一下codec => json的作用,就是直接输入预定义好的JSON数据,这样就可以省略掉filter/grok配置,其实就是可以省略在filter/grok中配置json插件配置了,codec默认值是plain,plain是一个空的解析器,它可以让用户自己指定格式。
|
|
MATCH_ALL是在{LOGSTASH_HOME}/patterns/postfix配置的grok表达式
|
|
也可以自己指定一个format格式,转换成String输出到指定端(ES,Kafka等等),注意format只对output生效
|
|
但是,仍然不解为何使用codec => “json”后,filter就获取不到原日志信息
再次尝试,仍然使用codec => “json”,但是在filter中添加match表达式,通过match中的”message”来获取原日志信息,然后把值复制给@message新字段,后续进行split拆分等等其他操作。具体配置文件修改如下:
|
|
尝试的结果并不是我们预期的,@message中获取的其实是我们track.log中的message字段的值”logs”。这里有个特殊情况就是我们track.log日志中带有message这个字段,但是为什么这里match表达式却获取到track.log日志中的message字段了呢?原因是我们input设置使用codec解码器为json(也就是将Logstash读取到我们file的原日志信息解析成json对象),match这里接收到的其实就是json对象中的message字段(就是我们track.log日志中的message字段),简单的理解match => {“message” => “%{MATCH_ALL:@message}”}就是通过”message”这个key获取filter接收的数据源(json对象或者原日志字符串)中的value,如果codec设置成json就是读取的json对象中的”message”的属性值,如果codec设置成plain,”message”是获取的原日志的字符串信息匹配grok表达式的值。
所以这里我们为了能够让match的”message”获取到原日志信息,而不是我们解析好的json日志中的message属性,我们把input的codec => “json”改成codec => “plain”,这样就会在input就将原日志解析成json对象了,而是我们在filter自己来处理。具体配置文件如下:
|
|
|
|
这里在使用split插件的过程中还发现了个Logstash的Bug,Split拆分的过程中如果遇到不是String和Array类型就会直接导致Logstash Crash,这里正确的做法应该类似grok一样,给对应的日志添加一个_jsonparsefailure的Tag,而不是导致Logstash直接崩溃,这个问题已经有人在GitHub上提了一个issue,貌似要等到Logstash 5.x的版本才会被修复。
具体地址:
参考文章: