লগস্ট্যাশ পার্সিং এক্সএমএল ডকুমেন্টে একাধিক লগ এন্ট্রি রয়েছে


8

লগস্ট্যাশ এবং ইলাস্টিক অনুসন্ধানটি আমাদের ব্যবহারের ক্ষেত্রে কার্যকর কিনা তা আমি বর্তমানে মূল্যায়ন করছি। আমার কাছে যা আছে তা হ'ল লগ ফাইল যা একাধিক এন্ট্রি ধারণ করে

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

প্রতিটি entryউপাদান একটি লগ ইভেন্ট থাকবে। (আপনি যদি আগ্রহী হন তবে ফাইলটি আসলে একটি টেম্পো টাইমসীট (একটি অ্যাটলাসিয়ান JIRA প্লাগ-ইন) ওয়ার্ক-লগ রফতানি))

আমার নিজের কোডেক না লিখে এই জাতীয় ফাইলটিকে একাধিক লগ ইভেন্টে রূপান্তর করা সম্ভব?

উত্তর:


11

ঠিক আছে, আমি একটি সমাধান পেয়েছি যা আমার পক্ষে কাজ করে। সমাধানটির সাথে সবচেয়ে বড় সমস্যাটি হ'ল এক্সএমএল প্লাগইনটি ... বেশ অস্থির নয়, তবে দুর্বল নথিভুক্ত এবং বগি বা দুর্বল ও ভুলভাবে নথিভুক্ত।

TLDR

কমান্ড লাইন:

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

লগস্ট্যাশ কনফিগারেশন:

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স্তর পর্যন্ত আমার এক্সএমএল ইনপুটটি খুব অভিন্ন এবং এইভাবে কোনও ধরণের প্যাটার্ন মেলানো দ্বারা পরিচালনা করা যেতে পারে।

যেহেতু রফতানিটি মূলত এক্সএমএলের একটি দীর্ঘ লাইন, এবং লগস্ট্যাশ এক্সএমএল প্লাগইন মূলত কেবল ক্ষেত্রগুলির সাথে কাজ করে (পড়ুন: লাইনে কলামগুলি) যাতে এক্সএমএল ডেটা থাকে, তাই আমাকে ডেটা আরও দরকারী ফর্ম্যাটে রূপান্তর করতে হয়েছিল।

শেল: ফাইল প্রস্তুত করা হচ্ছে

  • gzcat -d file.xml.gz |: খুব বেশি ডেটা ছিল - স্পষ্টতই আপনি এড়িয়ে যেতে পারেন
  • tr -d "\n\r" |: এক্সএমএল উপাদানগুলির মধ্যে লাইন-ব্রেকগুলি সরান: উপাদানগুলির মধ্যে কিছুতে চরিত্রের ডেটা হিসাবে লাইন বিরতি থাকতে পারে। পরবর্তী ধাপে প্রয়োজন যে এই সরিয়ে ফেলা হয়, অথবা কোনো না কোনোভাবে এনকোড। যদিও এটি ধরে নেওয়া হয়েছে যে এই মুহুর্তে আপনার কাছে সমস্ত এক্সএমএল কোড রয়েছে একটি বৃহত্তর লাইনে, এই আদেশটি উপাদানগুলির মধ্যে কোনও শ্বেত স্থান সরিয়ে দিলে কিছু যায় আসে না does

  • xmllint --format - |: এক্সমিলিন্টের সাথে এক্সএমএল ফর্ম্যাট করুন (লিবক্সিমিলের সাথে আসে)

    এখানে এক্সএমএলের একক বিশাল স্প্যাগেটি লাইনটি <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

logstash -f logstash-csv.conf

( .confটিএল; ডিআর বিভাগে ফাইলের সম্পূর্ণ সামগ্রী দেখুন ))

এখানে, 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>স্পেনের বেশি (বা হয় / এক্সমিলিন্ট ডিফল্টরূপে দুটি স্পেসের সাথে ইন্ডেন্টেশন করে) ইন্ডেন্টেশন সহ প্রতিটি লাইন পূর্ববর্তী লাইনের অন্তর্গত। এর অর্থ হ'ল চরিত্রের ডেটাতে অবশ্যই নতুন লাইন থাকা উচিত নয় ( trশেল দিয়ে স্ট্রিপ করা) এবং এক্সএমএলকে অবশ্যই স্বাভাবিকীকরণ করা হবে (xmllint)


হাই আপনি এই কাজটি করতে পরিচালনা করেছেন? আমি কৌতূহলী যেহেতু আমারও একই রকম প্রয়োজন এবং বিভাজনের সাথে মাল্টলাইন সমাধান আমার পক্ষে কার্যকর হয়নি। আপনার মতামতের জন্য ধন্যবাদ
যেমন

@ ভিজ এটি কাজ করেছে, তবে আমরা কখনও এটি উত্পাদন করতে ব্যবহার করি না। মাল্টিলাইন কেবল তখনই কাজ করে যদি আপনার খুব নিয়মিত এক্সএমএল কাঠামো থাকে এবং এটি ইন্ডেন্টেশনের সাথে প্রথমে ফর্ম্যাট করে (উত্তর দেখুন, বিভাগ "ফাইলটি প্রস্তুত করা হচ্ছে")
1515 এ ডুয়েলড

1

আমারও তেমন কেস হয়েছিল। এই এক্সএমএলটিকে বিশ্লেষণ করতে:

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

আমি আশা করি এটি কারও সাহায্য করতে পারে। এটি পেতে আমার অনেক দিন প্রয়োজন ছিল।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.