AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / server / 问题 / 615196
Accepted
dualed
dualed
Asked: 2014-07-25 06:14:54 +0800 CST2014-07-25 06:14:54 +0800 CST 2014-07-25 06:14:54 +0800 CST

Logstash 解析包含多个日志条目的 xml 文档

  • 772

我目前正在评估 logstash 和 elasticsearch 是否对我们的用例有用。我所拥有的是一个包含多个条目的日志文件,其形式为

<root>
    <entry>
        <fieldx>...</fieldx>
        <fieldy>...</fieldy>
        <fieldz>...</fieldz>
        ...
        <fieldarray>
            <fielda>...</fielda>
            <fielda>...</fielda>
            ...
        </fieldarray>
    </entry>
    <entry>
    ...
    </entry>
    ...
<root>

每个entry元素将包含一个日志事件。(如果您有兴趣,该文件实际上是一个 Tempo Timesheets (An Atlassian JIRA Plug-in) 工作日志导出。)

是否可以在不编写我自己的编解码器的情况下将这样的文件转换为多个日志事件?

xml
  • 2 2 个回答
  • 20406 Views

2 个回答

  • Voted
  1. Best Answer
    dualed
    2014-08-07T02:41:50+08:002014-08-07T02:41:50+08:00

    好吧,我找到了一个对我有用的解决方案。该解决方案的最大问题是 XML 插件......不是很不稳定,但要么记录不充分且存在错误,要么记录不充分且不正确。

    TLDR

    bash 命令行:

    gzcat -d file.xml.gz | tr -d "\n\r" | xmllint --format - | logstash -f logstash-csv.conf
    

    Logstash 配置:

    input {
        stdin {}
    }
    
    filter {
        # add all lines that have more indentation than double-space to the previous line
        multiline {
            pattern => "^\s\s(\s\s|\<\/entry\>)"
            what => previous
        }
        # multiline filter adds the tag "multiline" only to lines spanning multiple lines
        # We _only_ want those here.
        if "multiline" in [tags] {
            # Add the encoding line here. Could in theory extract this from the
            # first line with a clever filter. Not worth the effort at the moment.
            mutate {
                replace => ["message",'<?xml version="1.0" encoding="UTF-8" ?>%{message}']
            }
            # This filter exports the hierarchy into the field "entry". This will
            # create a very deep structure that elasticsearch does not really like.
            # Which is why I used add_field to flatten it.
            xml {
                target => entry
                source => message
                add_field => {
                    fieldx         => "%{[entry][fieldx]}"
                    fieldy         => "%{[entry][fieldy]}"
                    fieldz         => "%{[entry][fieldz]}"
                    # With deeper nested fields, the xml converter actually creates
                    # an array containing hashes, which is why you need the [0]
                    # -- took me ages to find out.
                    fielda         => "%{[entry][fieldarray][0][fielda]}"
                    fieldb         => "%{[entry][fieldarray][0][fieldb]}"
                    fieldc         => "%{[entry][fieldarray][0][fieldc]}"
                }
            }
            # Remove the intermediate fields before output. "message" contains the
            # original message (XML). You may or may-not want to keep that.
            mutate {
                remove_field => ["message"]
                remove_field => ["entry"]
            }
        }
    }
    
    output {
        ...
    }
    

    详细的

    我的解决方案有效,因为至少在entry关卡之前,我的 XML 输入非常统一,因此可以通过某种模式匹配来处理。

    由于导出基本上是一行非常长的 XML,而 logstash xml 插件基本上只适用于包含 XML 数据的字段(读取:行中的列),我不得不将数据更改为更有用的格式。

    Shell:准备文件

    • gzcat -d file.xml.gz |: 数据太多了——显然你可以跳过它
    • tr -d "\n\r" |:删除 XML 元素中的换行符:某些元素可以包含换行符作为字符数据。下一步需要将这些删除或以某种方式编码。尽管它假设此时您将所有 XML 代码放在一个大行中,但此命令是否删除元素之间的任何空白都无关紧要

    • xmllint --format - |: 用 xmllint 格式化 XML(libxml 自带)

      在这里,XML ( ) 的单个巨大的意大利面条行<root><entry><fieldx>...</fieldx></entry></root>格式正确:

      <root>
        <entry>
          <fieldx>...</fieldx>
          <fieldy>...</fieldy>
          <fieldz>...</fieldz>
          <fieldarray>
            <fielda>...</fielda>
            <fieldb>...</fieldb>
            ...
          </fieldarray>
        </entry>
        <entry>
          ...
        </entry>
        ...
      </root>
      

    日志存储

    logstash -f logstash-csv.conf
    

    .conf(请参阅TL;DR 部分中文件的完整内容。)

    在这里,multiline过滤器可以解决问题。它可以将多行合并为一条日志消息。这就是为什么需要格式化的原因xmllint:

    filter {
        # add all lines that have more indentation than double-space to the previous line
        multiline {
            pattern => "^\s\s(\s\s|\<\/entry\>)"
            what => previous
        }
    }
    

    这基本上说缩进超过两个空格的每一行(或者是</entry>/ xmllint 默认使用两个空格缩进)属于前一行。这也意味着字符数据不能包含换行符(tr在 shell 中被剥离)并且 xml 必须被规范化(xmllint)

    • 11
  2. rjurado01
    2016-12-24T04:14:55+08:002016-12-24T04:14:55+08:00

    我有一个类似的案例。要解析此 xml:

    <ROOT number="34">
      <EVENTLIST>
        <EVENT name="hey"/>
        <EVENT name="you"/>
      </EVENTLIST>
    </ROOT>
    

    我使用这个配置来登录:

    input {
      file {
        path => "/path/events.xml"
        start_position => "beginning"
        sincedb_path => "/dev/null"
        codec => multiline {
          pattern => "<ROOT"
          negate => "true"
          what => "previous"
          auto_flush_interval => 1
        }
      }
    }
    filter {
      xml {
        source => "message"
        target => "xml_content"
      }
      split {
        field => "xml_content[EVENTLIST]"
      }
      split {
        field => "xml_content[EVENTLIST][EVENT]"
      }
      mutate {
        add_field => { "number" => "%{xml_content[number]}" }
        add_field => { "name" => "%{xml_content[EVENTLIST][EVENT][name]}" }
        remove_field => ['xml_content', 'message', 'path']
      }
    }
    output {
      stdout {
        codec => rubydebug
      }
    }
    

    我希望这可以帮助某人。我需要很长时间才能得到它。

    • 1

相关问题

  • HP iLO 获取 XML 数据

  • 不会将整个 XML 文件读入内存的命令行 XML 验证器?

  • flash/flex 客户端上的套接字策略文件问题

  • 从命令行更新 XML [windows]

  • 开源 XML 防火墙?[关闭]

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    新安装后 postgres 的默认超级用户用户名/密码是什么?

    • 5 个回答
  • Marko Smith

    SFTP 使用什么端口?

    • 6 个回答
  • Marko Smith

    命令行列出 Windows Active Directory 组中的用户?

    • 9 个回答
  • Marko Smith

    什么是 Pem 文件,它与其他 OpenSSL 生成的密钥文件格式有何不同?

    • 3 个回答
  • Marko Smith

    如何确定bash变量是否为空?

    • 15 个回答
  • Martin Hope
    Tom Feiner 如何按大小对 du -h 输出进行排序 2009-02-26 05:42:42 +0800 CST
  • Martin Hope
    Noah Goodrich 什么是 Pem 文件,它与其他 OpenSSL 生成的密钥文件格式有何不同? 2009-05-19 18:24:42 +0800 CST
  • Martin Hope
    Brent 如何确定bash变量是否为空? 2009-05-13 09:54:48 +0800 CST
  • Martin Hope
    cletus 您如何找到在 Windows 中打开文件的进程? 2009-05-01 16:47:16 +0800 CST

热门标签

linux nginx windows networking ubuntu domain-name-system amazon-web-services active-directory apache-2.4 ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve