このエントリは「ウィークリーFluentdユースケースエントリリレー」への参加記事です。
ウィークリーFluentdユースケースエントリリレーまとめ(現在12本まで。) - iをgに変えるとorangeになることに気づいたoranieの日記
fluentd で一番手軽な出力 plugin といえば out_file ですね。path を指定するだけでファイルに出力できますが、使い方に気をつけないと落とし穴があるよ、という話です。
簡単な使いかた
一番単純な使いかたはこのような記述で、
<match app.**> type file path /path/to/logs/app.log </match>
これで /path/to/logs/app.log にJSON形式で出力されます。
2012-10-27T17:55:00+09:00 app.info {"message":"info message"} 2012-10-27T17:55:00+09:00 app.error {"message":"error message"}
out_file の仕様については tnmt さんが詳しく解説されていますので、そちらをご参照ください。fluentdのout_fileプラグインの仕様について - hack in 3 minites
よくあるユースケース
ところでよくあるユースケースとして、特定のレベルのみ (error, warn, info, debug のうち error のみとか)、特別な処理をしたいことがありますよね。
という処理をしたいとして、以下のように素直に記述してみるとどうなるか。
<match app.error> type mail host localhost from app@example.com to app-error@example.com subject app error! outkeys message </match> <match app.**> type file path /path/to/logs/app.log </match>
この記述では、app.error のタグにマッチしたログが out_mail に送られますが、後ろの app.** には到達しないため、ファイルには app.error は記録されません。残念。
複数箇所で同一 path を指定すると…
同一のログに対して複数回処理したい場合の定番パターンとして、copy plugin を使う方法があります。ではこのように書いてみます。
<match app.error> type copy <store> type file path /path/to/logs/app.log </store> <store> type mail host localhost from app@example.com to app-error@example.com subject app error! outkeys message </store> </match> <match app.**> type file path /path/to/logs/app.log </match>
app.error は copy で複製され、ファイルへの出力と mail 送信が行われるのを意図した記述です。が、これで出力ディレクトリを見てみると…
$ ls -l -rw-rw-r-- 1 fujiwara fujiwara 12586 Oct 27 18:09 app.log.20121027.b4cd06c6c03a45069 -rw-rw-r-- 1 fujiwara fujiwara 12992 Oct 27 18:09 app.log.20121027.b4cd06c6c03be61ae
なぜか2ファイル生成されています。out_file は記述ごとにファイル出力を行うため、同一の path を指定しても別ファイルとして出力されるのです。これでは、app.error とそれ以外の内容が別ファイルに分かれてしまいます。
また、ファイル末尾の .b4cd06c6... の部分はローテートされるときに .0 .1 .2 のように rename されるのですが、同一のファイル名での出力記述がある場合、ごく稀に以下のようなエラーが発生することがあります。
error on output thread error="No such file or directory - (/path/to/logs/app.log.20121027.b4cce432670682745, /path/to/logs/app.log.20121027.b4cce432670682745)"
『out_file で 同一の path を複数箇所で指定することはできない』
一見普通にできそうなのですが問題が発生するパターンなので、覚えておきましょう。
過去のバージョンでの経験で現在の最新版では再現できなかったのですが、同一pathを指定していた場合のローテート処理のエラーで、fluentd が処理を停止してしまった経験もあります。
ではどうすれば?
標準のプラグインではありませんが、fluent-plugin-rewrite を使用してタグを書き換えてやることで可能になります。
fluent-plugin-rewriteというプラグインを作成した #fluentd - delirious thoughts
<match app.error> type copy <store> type rewrite add_prefix filtered </store> <store> type mail # 略 </store> </match> <match app.**> type rewrite add_prefix filtered </match> <match filtered.app.**> type file path /path/to/logs/app.log </match>
- app.error は copy で複製され、
- rewrite によって filtered.app.error にタグが書き換えられる
- mail によってメール送信
- それ以外の app.** は rewrite によって filtered.app.error にタグが書き換えられる
- filtered.app.** をファイルに出力
という流れになります。