【问题标题】:Parse multiline JSON with grok in logstash在 logstash 中使用 grok 解析多行 JSON
【发布时间】:2014-08-31 01:33:05
【问题描述】:

我有一个 JSON 格式:

{
    "SOURCE":"Source A",
    "Model":"ModelABC",
    "Qty":"3"
}

我正在尝试使用 logstash 解析这个 JSON。基本上,我希望logstash 输出是可以使用kibana 分析的键:值对列表。我认为这可以开箱即用。从大量阅读中,我知道我必须使用 grok 插件(我仍然不确定 json 插件的用途)。但我无法获得所有领域的事件。我得到了多个事件(甚至对于我的 JSON 的每个属性都有一个)。像这样:

{
       "message" => "  \"SOURCE\": \"Source A\",",
      "@version" => "1",
    "@timestamp" => "2014-08-31T01:26:23.432Z",
          "type" => "my-json",
          "tags" => [
        [0] "tag-json"
    ],
          "host" => "myserver.example.com",
          "path" => "/opt/mount/ELK/json/mytestjson.json"
}
{
       "message" => "  \"Model\": \"ModelABC\",",
      "@version" => "1",
    "@timestamp" => "2014-08-31T01:26:23.438Z",
          "type" => "my-json",
          "tags" => [
        [0] "tag-json"
    ],
          "host" => "myserver.example.com",
          "path" => "/opt/mount/ELK/json/mytestjson.json"
}
{
       "message" => "  \"Qty\": \"3\",",
      "@version" => "1",
    "@timestamp" => "2014-08-31T01:26:23.438Z",
          "type" => "my-json",
          "tags" => [
        [0] "tag-json"
    ],
          "host" => "myserver.example.com",
          "path" => "/opt/mount/ELK/json/mytestjson.json"
}

我应该使用多行编解码器还是 json_lines 编解码器?如果是这样,我该怎么做?我是否需要编写自己的 grok 模式,或者是否有一些通用的 JSON 可以给我一个带有键的事件:我为上面的一个事件获得的值对?我找不到任何说明这一点的文档。任何帮助,将不胜感激。我的conf文件如下所示:

input
{
        file
        {
                type => "my-json"
                path => ["/opt/mount/ELK/json/mytestjson.json"]
                codec => json
                tags => "tag-json"
        }
}

filter
{
   if [type] == "my-json"
   {
        date { locale => "en"  match => [ "RECEIVE-TIMESTAMP", "yyyy-mm-dd HH:mm:ss" ] }
   }
}

output
{
        elasticsearch
        {
                host => localhost
        }
        stdout { codec => rubydebug }
}

【问题讨论】:

    标签: json elasticsearch logstash logstash-grok


    【解决方案1】:

    我想我找到了解决问题的有效方法。我不确定它是否是一个干净的解决方案,但它有助于解析上述类型的多行 JSON。

    input 
    {   
        file 
        {
            codec => multiline
            {
                pattern => '^\{'
                negate => true
                what => previous                
            }
            path => ["/opt/mount/ELK/json/*.json"]
            start_position => "beginning"
            sincedb_path => "/dev/null"
            exclude => "*.gz"
        }
    }
    
    filter 
    {
        mutate
        {
            replace => [ "message", "%{message}}" ]
            gsub => [ 'message','\n','']
        }
        if [message] =~ /^{.*}$/ 
        {
            json { source => message }
        }
    
    }
    
    output 
    { 
        stdout { codec => rubydebug }
    }
    

    我的多行编解码器不处理最后一个大括号,因此它不会以 JSON 格式显示给json { source => message }。因此变异过滤器:

    replace => [ "message", "%{message}}" ]
    

    这增加了缺少的大括号。和

    gsub => [ 'message','\n','']
    

    删除引入的\n 字符。最后,我有一个可以被json { source => message }读取的单行JSON

    如果有一种更简洁/更简单的方法可以将原始多行 JSON 转换为单行 JSON,请执行 POST,因为我觉得上面的内容不太干净。

    【讨论】:

      【解决方案2】:

      您需要使用multiline 编解码器。

      input {
        file {
          codec => multiline {
              pattern => '^{'
              negate => true
              what => previous
          }
          path => ['/opt/mount/ELK/json/mytestjson.json']
        }
      }
      filter {
        json {
          source => message
          remove_field => message
        }
      }
      

      您将遇到的问题与文件中的最后一个事件有关。在文件中有另一个事件之前它不会显示(所以基本上你会丢失文件中的最后一个事件)——你可以在文件被旋转之前附加一个 { 到文件以处理这种情况.

      【讨论】:

      • 感谢 Alcanzar,虽然我得到了 JSON 解析失败:[0] "_jsonparsefailure" 尝试将模式更改为模式 => '^\{' 但仍然相同。我的文件每个文件只有 1 个 JSON,即只有一个 { 或 } 字符。每个文件将是一个事件(1 个文件 = 1 个 JSON =1 个事件)
      • 您可能需要在文件输入中添加start_postion => beginning 以确保它从记录的开头开始...您的文件中还有其他内容吗? (您可以删除过滤器并添加 output { stdout {} } 以查看它收集的内容以传递给 json 过滤器)
      • 我注意到我的生产 JSON 确实有额外的 "{" 和 "}" :( 所以我的 JSON 实际上是: { "SOURCE":"Source A", "Model":"ModelABC", "Qty":"3" "DESC": "{\"New prod-125\"}" } (抱歉在 cmets 中解析不好)我无法对这些 JSON 进行更改。我们从另一个接收到它们来源,我需要按原样消费。
      • 您必须先“修复”该消息,然后再对其执行json。例如,您可以使用mutate 过滤器和gsub => [ 'message','\"',''] 如果您需要更复杂的东西,您可以使用ruby 代码过滤器
      • 我认为这可以归结为将我的多行 JSON(由大括号限制)减少到一行,然后我可以应用过滤器:if [message] =~ /^{.*}$/ {json { source => message } }。如何将我的多行 JSON 减少到一行?我不是红宝石人,所以我不能那样做。有小费吗?奇怪的是我找不到其他必须解析多行 JSON 的人
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-03-31
      • 1970-01-01
      • 1970-01-01
      • 2019-06-22
      • 2020-11-10
      • 2015-12-18
      • 1970-01-01
      相关资源
      最近更新 更多