여러 로그 항목을 포함하는 Logstash 구문 분석 XML 문서

현재 logstash와 elasticsearch가 사용 사례에 유용한 지 평가하고 있습니다. 내가 가진 것은 형식의 여러 항목을 포함 하는 로그 파일 입니다

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

entry요소에는 하나의 로그 이벤트가 포함됩니다. (관심이 있다면 파일은 실제로 템포 작업 표 (아틀라스 식 JIRA 플러그인) 작업 로그 내보내기입니다.)

자체 코덱을 작성하지 않고도 이러한 파일을 여러 로그 이벤트로 변환 할 수 있습니까?



답변

좋아, 나에게 맞는 해결책을 찾았다. 솔루션의 가장 큰 문제는 XML 플러그인이 … 불안정하지는 않지만 잘못 문서화되고 버그가 있거나 잘못 문서화된다는 것입니다.

TLDR

배쉬 커맨드 라인 :

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 데이터가 포함 된 필드 (읽기 : 열의 열)에서만 작동하므로 데이터를보다 유용한 형식으로 변경해야했습니다.

셸 : 파일 준비

  • 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

( .confTL; 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쉘로 묶여) XML이 정규화되어야 함을 의미합니다 (xmllint)


답변

나는 비슷한 경우가 있었다. 이 XML을 구문 분석하려면 다음을 수행하십시오.

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

이 구성을 사용하여 logstash를 수행합니다.

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
  }
}

이것이 누군가를 도울 수 있기를 바랍니다. 그것을 얻기 위해 오랜 시간이 필요했습니다.


답변