如何通过Grok Filter检测Logstash日志message中stack_trace是否存在
问题分析与解决方案
你的问题核心在于:Logstash当前只是把收到的日志内容作为字符串存在message字段中,没有解析其中的JSON结构,所以直接用[message][stack_trace]去访问嵌套字段是无效的——因为message是字符串,不是可访问的哈希对象。
为什么会这样?
你用logstash-logback-encoder生成的是标准JSON格式的日志,但Logstash的tcp输入插件默认会把接收到的所有内容当成纯文本存入message字段,不会自动解析JSON。所以即使message里包含stack_trace字段,Logstash也识别不到它的结构。
解决步骤
我们需要先把message字段中的JSON字符串解析成结构化的事件字段,之后才能检测stack_trace是否存在。同时要兼容你现有处理非JSON日志的grok规则,所以需要加条件判断区分两种日志类型:
修改后的Logstash Filter配置
filter { # 先处理JSON格式的日志(来自logstash-logback-encoder) if [message] =~ /^{.*}$/ { json { source => "message" # 可选:如果想保留原始message字符串,添加target参数,解析后的内容会存在log_details字段下 # target => "log_details" } # 现在可以直接检测stack_trace字段了(如果用了target,就改成[log_details][stack_trace]) if [stack_trace] { mutate { add_tag => ["EXCEPTION"] } } } else { # 处理非JSON格式的日志,沿用你原来的grok和mutate规则 grok { match => { "message" => "LAT: %{NUMBER:LAT:float}, LON: %{NUMBER:LON:float}" } match => { "message" => "file %{WORD:TIPOFILE} elaborato" } match => { "message" => "Pubblicazione file %{WORD:PUB_FILENAME} sulla coda %{WORD:DEST_QUEUE} terminata" } } mutate { rename => { "TIPOFILE" => "[filename]" } rename => { "LAT" => "[location][latitude]" } rename => { "LON" => "[location][longitude]" } rename => { "DEST_QUEUE" => "[destQueue]" } rename => { "PUB_FILENAME" => "[nomeFilePubbl]" } } } }
关键细节说明
- JSON解析判断:用
[message] =~ /^{.*}$/简单判断message是否是JSON格式(以{开头、}结尾),避免对非JSON日志执行解析操作。 json过滤器的作用:source => "message"指定要解析的字段是message,解析后会把JSON里的键值对直接展开成Logstash事件的顶级字段(比如@timestamp、thread、stack_trace等)。如果不想覆盖原始message,就加上target => "log_details",之后访问stack_trace要写成[log_details][stack_trace]。- 标签添加逻辑:解析完成后,直接判断
[stack_trace](或[log_details][stack_trace])是否存在,存在就添加EXCEPTION标签。
验证方法
修改配置后重启Logstash,通过stdout { codec => rubydebug }输出查看事件结构:
- 对于JSON日志,你会看到
stack_trace字段(或log_details下的stack_trace),且当该字段存在时,tags数组里会包含EXCEPTION。 - 非JSON日志会正常走原来的
grok处理流程。
内容的提问来源于stack exchange,提问作者Alessio Frabotta
相关产品推荐
相关产品推荐

