【问题标题】:Fluentd does not parse nested json arrayFluentd 不解析嵌套的 json 数组
【发布时间】:2021-05-12 14:48:54
【问题描述】:

我在 Fluentd 输入上有以下 json 消息

{"foo":{"bar":{"abc":"[\n {\n \"ip\":\"192.168.1.1\",\n \"hostname\":\"pc\",\n \"mac\":\"01:02:03:04:05:06\"\n} \n]"}}}

又想得到输出消息

{"foo":{"bar":{"abc":[{"ip":"192.168.1.1", "hostname":"pc", "mac":"01:02:03:04:05:06}]"}}}

我正在尝试用过滤器解析它

<filter **>
  @type parser
  key_name foo
  reserve_data true
  remove_key_name_field false
  <parse>
    @type multi_format
    <pattern>
      format json
    </pattern>
    <pattern>
      format none
    </pattern>
  </parse>
</filter>  

但是没有任何效果。输出与输入相同。

当我尝试时

<filter **>
  @type parser
  key_name $['foo']['bar']['abc']
  <parse>
    @type none
  </parse>
</filter>

<filter **>
  @type parser
  key_name message
  <parse>
    @type json
  </parse>
</filter>

它“有效”,但我当然只得到

[{"ip":"192.168.1.1","hostname":"ps","mac":"01:02:03:04:05:06}]

感谢您的建议。

【问题讨论】:

  • 我的理解是,您收到的消息包含转义字符,并且您想要清除它们,对吧? source 是什么?请edit 并添加source 部分。
  • @Azeem 是的,你是对的“清理转义字符”&lt;sourse&gt; 在这种情况下无关紧要,可以是任何东西 - 虚拟、样本、转发等。
  • 好吧,如果你得到硬编码的转义字符,如上例所示,清理/转换这些字符的一种方法是通过启用 Ruby 使用record_transformer 过滤器插件。你可以试试看。
  • @Azeem 但如何?你能推荐任何代码吗?
  • 请参考文档:docs.fluentd.org/filter/record_transformer#enable_ruby。在块中,您可以使用 ruby​​ 代码。例如,请参阅此线程:stackoverflow.com/questions/1634750/…。

标签: fluentd


【解决方案1】:

您可以像这样使用record_transformer by enabling Ruby:

<filter **>
  @type record_transformer
  enable_ruby true
  <record>
    message ${ record['message'].gsub(/(\\n)|(\\)|(\s+)/, '') }
  </record>
</filter>

输出:

2021-05-17 16:22:14.568177376 +0500 test.*: {"message":"{\"foo\":{\"bar\":{\"abc\":\"[{\"ip\":\"192.168.1.1\",\"hostname\":\"pc\",\"mac\":\"01:02:03:04:05:06\"}]\"}}}"}

输出puts:

{"foo":{"bar":{"abc":"[{"ip":"192.168.1.1","hostname":"pc","mac":"01:02:03:04:05:06"}]"}}}

用引号括起来的数组是一个 JSON 值。要使其成为有效的 JSON 数组,还应删除其引号。

所以,要做到这一点,你会使用这样的东西:

s.gsub(/(\\n)|(\\)|(\s+)/, '').gsub(/\"\[/, '[').gsub(/\]\"/, ']')

这是完整的测试:

fluent.conf

<source>
  @type forward
  bind 0.0.0.0
  port 8080
  tag test.*
</source>

<filter **>
  @type record_transformer
  enable_ruby true
  <record>
    # message ${ record['message'].gsub(/(\\n)|(\\)|(\s+)/, '') }
    message ${ m = record['message'].gsub(/(\\n)|(\\)|(\s+)/, ''); puts m; m; }
  </record>
</filter>

<match **.*>
  @type stdout
</match>

运行fluentd:

fluentd -c fluent.conf

用fluent-cat向fluentd发送消息:

echo '{"foo":{"bar":{"abc":"[\n  {\n  \"ip\":\"192.168.1.1\",\n  \"hostname\":\"pc\",\n  \"mac\":\"01:02:03:04:05:06\"\n}  \n]"}}}' | fluent-cat -p 8080 -f none test

fluentd 日志中的输出:

{"foo":{"bar":{"abc":"[{"ip":"192.168.1.1","hostname":"pc","mac":"01:02:03:04:05:06"}]"}}}
2021-05-17 16:22:14.568177376 +0500 test.*: {"message":"{\"foo\":{\"bar\":{\"abc\":\"[{\"ip\":\"192.168.1.1\",\"hostname\":\"pc\",\"mac\":\"01:02:03:04:05:06\"}]\"}}}"}

【讨论】:

  • 非常感谢您的建议但是可以输出为2021-05-17 16:22:14.568177376 +0500 test.*: {"foo":{"bar":{"abc":"[{"ip":"192.168.1.1","hostname":"pc","mac":"01:02:03:04:05:06"}]"}}} 吗?
  • @user15821532:但是,为什么?你的用例是什么?您要将这些日志转储到哪里?实际日志是message 的值,键本身即message 不是其中的一部分。
  • 到 elasticsearch 对不起,我可能是愚蠢的问题,我是 EFK 的新手
  • @user15821532:不用担心。使用此配置并将数据发送到 ElasticSearch。它应该工作得很好。这里的最终输出是清理后的有效 JSON。如果有任何问题,请告诉我。
【解决方案2】:

这会解析未解析的嵌套 json

<filter **>
  @type parser
  key_name $['foo']['bar']['abc']
  hash_value_field parsed_abc
  reserve_data true
  remove_key_name_field true
  <parse>
    @type json
  </parse>
</filter>

<filter **>
  @type record_transformer
  enable_ruby true
  <record>
    parsed_abc ${record['foo']['bar']['abc'] = record['parsed_abc']}
  </record>
  remove_keys parsed_abc
</filter>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多