Logstash 将 xml 拆分为数组

Logstash split xml into array

是否可以使用 logstash 将 xml 转换为对象数组?

那是我的示例文档:

{
  "Title" : "My blog title",
  "Body" : "My first post ever",
  "Metadata" : "<root><Tags><TagTypeID>1</TagTypeID><TagValue>twitter</TagValue></Tags><Tags><TagTypeID>1</TagTypeID><TagValue>facebook</TagValue></Tags><Tags><TagTypeID>2</TagTypeID><TagValue>usa</TagValue></Tags><Tags><TagTypeID>3</TagTypeID><TagValue>smartphones</TagValue></Tags></root>"
}

理想情况下,我想输出这个:

{
  "Title" : "My blog title",
  "Body" : "My first post ever",
  "Metadata" : [
    {
      "TagTypeID" : "1",
      "TagValue" : "twitter"
    },
    {
      "TagTypeID" : "1",
      "TagValue" : "facebook"
    },
    {
      "TagTypeID" : "2",
      "TagValue" : "usa"
    },
    {
      "TagTypeID" : "3",
      "TagValue" : "smartphones"
    }
  ]
}

但是我无法做到这一点。我试过像这样使用 xml 过滤器:

xml
{
    source => "Metadata"
    target => "Parsed"
}

然而,它输出这个

{
  "Title" : "My blog title",
  "Body" : "My first post ever",
  "@version" : "1",
  "@timestamp" : "2015-10-27T17:21:31.961Z",
  "Parsed" : {
    "Tags" : [
      {
        "TagTypeID" : ["1"],
        "TagValue" : ["twitter"]
      },
      {
        "TagTypeID" : ["1"],
        "TagValue" : ["facebook"]
      },
      {
        "TagTypeID" : ["2"],
        "TagValue" : ["usa"]
      },
      {
        "TagTypeID" : ["3"],
        "TagValue" : ["smartphones"]
      }
    ]
  }
}

我不希望我的值存储为数组(我知道那里总是只有一个值)。

我知道我的输入会带回哪些字段,所以我可以自己映射结构,这不需要是动态的(尽管那会很好)。

Allow splitting of lists / arrays into multiple events 似乎很有用,但它的文档很少,我找不到关于如何在我的用例中使用此过滤器的信息。

Logstash, split event from an xml file in multiples documents keeping information from root tags 类似,但不完全是我想要实现的。

这似乎很有用,但是它硬编码了数组的第一个元素必须作为单个项目(不是数组的一部分)输出。它让我想起了这个:

{
  "Title" : "My blog title",
  "Body" : "My first post ever",
  "@version" : "1",
  "@timestamp" : "2015-10-27T17:21:31.961Z",
  "Parsed" : {
    "Tags" : [
      {
        "TagTypeID" : "1",
        "TagValue" : "twitter"
      },
      {
        "TagTypeID" : ["1"],
        "TagValue" : ["facebook"]
      },
      {
        "TagTypeID" : ["2"],
        "TagValue" : ["usa"]
      },
      {
        "TagTypeID" : ["3"],
        "TagValue" : ["smartphones"]
      }
    ]
  }
}
  1. 无需创建自定义过滤器就可以做到这一点吗? (我没有 Ruby)
  2. 的经验
  3. 还是我遗漏了一些基本的东西?

这是一种使用 logstash 内置函数的方法 ruby filter

过滤部分:

filter {
    xml {
        source => "Metadata"
        target => "Parsed"
    }

    ruby {  code => "
        event['Parsed']['Tags'].each do |x|
            x.each do |key, value|
                x[key] = value[0]
            end
        end"
    }
}

输出:

"Parsed":{
  "Tags":[
      {
      "TagTypeID":"1",
      "TagValue":"twitter"
      },
      {
      "TagTypeID":"1",
      "TagValue":"facebook"
      },
      {
      "TagTypeID":"2",
      "TagValue":"usa"
      },
      {
      "TagTypeID":"3",
      "TagValue":"smartphones"
      }
  ]
}

如果我理解正确的话,这就是你想要的结果。您需要在 ruby 过滤器中指定 xml 字段:event['Parsed']['Tags']。它需要更有活力吗?如果您还需要什么,请告诉我。

Can this be done without having to create custom filters? (I've no experience in Ruby)

好吧,是的,也不是。是的,因为这实际上不是自定义过滤器,而是内置解决方案。不,因为我倾向于说没有 Ruby 就无法做到这一点。我必须承认 Ruby 似乎是一个没有吸引力的解决方案。然而,这是一种灵活的方法,5 行代码应该不会造成太大伤害。

最新的 Logstash 版本(此时为 5.1.1)更新了 XML 过滤器,其中有 force_array 选项。默认情况下启用。将此设置为 false 将执行与已接受答案中的 ruby 过滤器完全相同的操作。

摘自文档:

force_contentedit

  • Value type is boolean
  • Default value is false

By default the filter will expand attributes differently from content inside of tags. This option allows you to force text content and attributes to always parse to a hash value.

https://www.elastic.co/guide/en/logstash/current/plugins-filters-xml.html#plugins-filters-xml-force_array