需求
在调用一个方法时会打印一条日志:
{"bizId":"45149684156451","name":"zs","hobby":"book"}
同时会有一个定时任务每10秒执行一次,并且也会打印一条日志
{"bizId":"45149684156451","age":26}
这两条日志的关联性就是其中的bizId。
现在的需求是:将bizId相同的日志通过logstash输出为一条日志,即一个事件。
如果不做任何处理的话,那么logstash将会把每一条日志作为一个事件来输出。这样不符合需求,为此需要通过logstash的聚合插件来解决。
方案
logstash配置:
#输入方式:控制台
input {
stdin{}
}
filter{
#将采集到的日志分割为一个个json字段
json {
source => "message"
}
#对同一个task_id的日志做聚合处理
aggregate{
#聚合的依据:bizId
task_id => "%{bizId}"
#聚合动作:获取以上得到的json字段并赋值给map中相应的字段
code => "
map['bizId'] ||= event.get('bizId')
map['name'] ||= event.get('name')
map['hobby'] ||= event.get('hobby')
map['age'] ||= event.get('age')
#相同bizId的日志不输出,只有当超时或者聚合完成后才作为一条日志输出,因为我们最终目标是只输出聚合后的一条日志
event.cancel()
"
#当检测到不同的task_id时,就会将之前聚合的map作为一个新的事件并立即推送,然后以新的task_id建立新的聚合事件等待聚合
#push_previous_map_as_event => true
#直到超时才将聚合的map作为事件进行推送
push_map_as_event_on_timeout => true
#超时后将事件打一个新的标签。这个配置至关重要,如果要将聚合后的事件推送到ES(output中根据该标签来新建一个ES索引),那么必须有这个设置,否则ES得不到推送的数据
timeout_tags => ["my_aggr"]
#超时时间:在该时间内如果没有相同的task_id日志,那么就将已经采集到的日志输出为一个事件
#超时时间的设置至关重要,决定了能否将需要关联的日志聚合为一条日志,具体取决于业务
timeout => 7
}
}
#输出方式:控制台
output {
stdout{
codec => "rubydebug"
}
}
测试结果:
The stdin plugin is now waiting for input:
{"bizId":"45149684156451","name":"zs","hobby":"book"}
{"bizId":"45149684156451","age":26}
{
"name" => "zs",
"age" => 26,
"@version" => "1",
"bizId" => "45149684156451",
"hobby" => "book",
"@timestamp" => 2022-06-15T06:39:53.001Z
}
还有其他场景的解决方法可以参考官方文档提供的几个案例:
参考