如何使用logstash过滤器处理多行日志条目?

时间:2014-03-04 13:10:05

标签: regex logstash multiline logstash-grok

背景:

我有一个自定义生成的日志文件,其格式如下:

[2014-03-02 17:34:20] - 127.0.0.1|ERROR| E:\xampp\htdocs\test.php|123|subject|The error message goes here ; array (
  'create' => 
  array (
    'key1' => 'value1',
    'key2' => 'value2',
    'key3' => 'value3'
  ),
)
[2014-03-02 17:34:20] - 127.0.0.1|DEBUG| flush_multi_line

第二个条目[2014-03-02 17:34:20] - 127.0.0.1|DEBUG| flush_multi_line是一个虚拟行,只是为了让logstash知道多行事件已经结束,以后会删除此行。

我的配置文件如下:

input {
  stdin{}
}

filter{
  multiline{
      pattern => "^\["
      what => "previous"
      negate=> true
  }
  grok{
    match => ['message',"\[.+\] - %{IP:ip}\|%{LOGLEVEL:loglevel}"]
  }

  if [loglevel] == "DEBUG"{ # the event flush  line
    drop{}
  }else if [loglevel] == "ERROR"  { # the first line of multievent
    grok{
      match => ['message',".+\|.+\| %{PATH:file}\|%{NUMBER:line}\|%{WORD:tag}\|%{GREEDYDATA:content}"] 
    }
  }else{ # its a new line (from the multi line event)
    mutate{
      replace => ["content", "%{content} %{message}"] # Supposing each new line will override the message field
    }
  }  
}

output {
  stdout{ debug=>true }
}

内容字段的输出为:The error message goes here ; array (

问题:

我的问题是我想将多行的其余部分存储到内容字段:

The error message goes here ; array (
  'create' => 
  array (
    'key1' => 'value1',
    'key2' => 'value2',
    'key3' => 'value3'
  ),
)

所以我可以稍后删除消息字段。

@message 字段包含整个多行事件,因此我尝试使用 mutate过滤器,并使用替换函数,但我&# 39;我只是无法让它发挥作用:(。

我不了解Multiline过滤器的工作方式,如果有人能对此有所了解,我们将非常感激。

谢谢,

阿卜杜迪。

4 个答案:

答案 0 :(得分:12)

我浏览了源代码并发现:

  • 多行过滤器将取消所有被认为是待处理事件的后续行为的事件,然后将该行附加到原始消息字段,即任何在这种情况下,多行过滤器之后的过滤器将不适用
  • 唯一可以通过过滤器的事件是被认为是新事件的事件(在我的情况下以 [开头)

以下是工作代码:

input {
   stdin{}
}  

filter{
      if "|ERROR|" in [message]{ #if this is the 1st message in many lines message
      grok{
        match => ['message',"\[.+\] - %{IP:ip}\|%{LOGLEVEL:loglevel}\| %{PATH:file}\|%{NUMBER:line}\|%{WORD:tag}\|%{GREEDYDATA:content}"]
      }

      mutate {
        replace => [ "message", "%{content}" ] #replace the message field with the content field ( so it auto append later in it )
        remove_field => ["content"] # we no longer need this field
      }
    }

    multiline{ #Nothing will pass this filter unless it is a new event ( new [2014-03-02 1.... )
        pattern => "^\["
        what => "previous"
        negate=> true
    }

    if "|DEBUG| flush_multi_line" in [message]{
      drop{} # We don't need the dummy line so drop it
    }
}

output {
  stdout{ debug=>true }
}

干杯,

阿卜杜迪

答案 1 :(得分:10)

本期https://logstash.jira.com/browse/LOGSTASH-509

中提到了grok和多行处理

只需添加"(?m)"在你的grok正则表达式面前,你不会需要变异。问题示例:

pattern => "(?m)<%{POSINT:syslog_pri}>(?:%{SPACE})%{GREEDYDATA:message_remainder}"

答案 2 :(得分:5)

多行过滤器会在消息中添加“\ n”。例如:

"[2014-03-02 17:34:20] - 127.0.0.1|ERROR| E:\\xampp\\htdocs\\test.php|123|subject|The error message goes here ; array (\n  'create' => \n  array (\n    'key1' => 'value1',\n    'key2' => 'value2',\n    'key3' => 'value3'\n  ),\n)"

但是,grok过滤器无法解析“\ n”。因此,您需要将\ n替换为另一个字符,即空格。

mutate {
    gsub => ['message', "\n", " "]
}

然后,grok模式可以解析消息。例如:

 "content" => "The error message goes here ; array (   'create' =>    array (     'key1' => 'value1',     'key2' => 'value2',     'key3' => 'value3'   ), )"

答案 3 :(得分:1)

问题不仅仅是过滤器的排序。记录存储顺序非常重要。您不需要另一行来指示您已完成输出多行日志行。只需确保在grok之前首先出现多行过滤器(见下文)

P.S。我已经设法解析了多行日志行,其中xml被附加到日志行的末尾并且它跨越了多行但仍然有一个很好的干净xml对象到我的内容等效变量(下面名为xmlrequest)。在你说一些关于在日志中记录xml的事情之前......我知道......它不理想......但这是另一场辩论:)):

filter { 
multiline{
        pattern => "^\["
        what => "previous"
        negate=> true
    }

mutate {
    gsub => ['message', "\n", " "]
}

mutate {
    gsub => ['message', "\r", " "]
}

grok{
        match => ['message',"\[%{WORD:ONE}\] \[%{WORD:TWO}\] \[%{WORD:THREE}\] %{GREEDYDATA:xmlrequest}"]
    }

xml {
source => xmlrequest
remove_field => xmlrequest
target => "request"
  }
}