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