Posted at

fluentdのカスタムParser Pluginを作ってみる

More than 5 years have passed since last update.


なぜParser Pluginが必要なのか。

独自フォーマットのログをパースするときに、デフォルトのin_tail pluginの正規表現では対応が難しい場合ががあります。

例えば、下記のログが挙げられます。

このログは、Key=Valueが順不同で発生したり、そもそも発生してたりしていなかったりしてます。

さらに要求として、keyをカラム名にValueを値という形で使いたい場合にはどうすればよいでしょうか。

[2013-01-01 00:00:00] key1=value1&key2=value2

[2013-01-01 00:00:00] key2=value2&key1=value1&key3=value3

このような場合では、fluentdのParser Pluginを作るとで対応することができます。

その他の案として、Tailインプットプラグインパーサーをカスタマイズすることもできますが、

こちらの方法だとread_from_headerなどの最近追加されたオプションが使えません。

オプションが追加されたNewTailInput pluginを同様の方法で作成する方法もありますが、

少々NewTailInputが複雑そうなので今回はやめておきます。

それぞれの方法のサンプルとなるpluginを挙げます。


Parser Pluginを作る

それでは、Parser Pluginを作ります。

サンプルは下記です。

# filename: parser_test_format.rb

require 'fluent/parser'

module Fluent
class TextParser
class TestFormatParser # TestFormatParserを任意変更
include Configurable

def initialize
super
end
def configure(conf)
super
@time_format = conf['time_format'] || '%Y-%m-%d %H:%M:%S'
end
def call(text)
# begin: 1レコードを編集処理
elements = /^\[(.+)\] (.+)$/.match(text)

time = elements[1]
time = Time.strptime(time, @time_format).to_i

# key1=value1&key2=value2&... -> [key1=value1, key2=value2, ...]
messages = elements[2].split('&')

# [k1, v1, k2, v2, ...] -> {k1=>v1, k2=>v2, ...}
record = {}
messages.each do |message|
kv = message.split('=')
while (k = kv.shift) && (v = kv.shift)
record[k] = v
end
end
# end

if time && record
if block_given?
yield time, record
return
else
return time, record
end
end
rescue # ignore parser error
end
end

# test_formatとTestFormatParserを任意変更
register_template('test_format', Proc.new { TestFormatParser.new })
end
end


Parser Pluginを使う

設定ファイルは下記の通りに記載します。

Gem化していない場合は、td-agentの場合には、/etc/fluent/pluginフォルダ以下に格納します。

あとは通常通りにfluentdを起動すれば大丈夫です。

NewTailInputを使うことができるので、read_from_head等のオプションも利用できます。

<source>

type tail
tag test.parser
format test_format # registerで指定した名前
path /var/log/test/test.log
pos_file /var/log/td-agent/test.pos
read_from_head true
</source>


まとめ

ログは、ログをパースすることも考えて、プログラミングでインプットが容易なログのフォーマットで保存するようにしましょう。

ログサイズは大きくなりますが、LTSV形式とかをおすすめしておきます。

ストレージを気にする時代でもないので、1レコードのサイズが大きくなっても問題ないでしょう。