fluentdのプラグインとかユースケースの話
この記事は「ウィークリー Fluentd ユースケースエントリリレー」の一部です。カジュアルに fluentd のプラグイン書いてみた話とリアルタイム監視のよくあるパターンを書いてみます。
groupcounter
モヒカン族で有名な tagomoris さんが書かれたdatacounterというプラグインをパクって書きました。ある key に対する value を一定期間カウントしたい時に使います。ユースケースとしては、access log から src IP ごとの件数を毎分数えて、グラフにすると、どの IP からのリクエストがどういう推移をしてるかが観測できます。
config はこんな感じ。
<match apache.access>
type groupcounter
count_interval 5s
aggregate tag
output_per_tag true
tag_prefix groupcounter
group_by_keys code,method,path
</match>
なんで作ったかいうと、datacounter は予め決めたいくつかのパターンにマッチするものを数えるものなので、IP アドレスのように種類が不定だと使えません。ちなみに、数値に対してレンジごとにカウントするならnumeric-counterがよいと思います。
hash-forward
ちょっと特殊な forward プラグインです。通常 forward は server に並べたやつのどれかに適当にラウンドロビンで送りますが、たまに同じタグは同じ fluentd に必ず送って欲しい場面があります。
例えば先に書いたカウント系の plugin を使って出力元のホスト毎にカウントしつつ、スケールアウトしたいなら、あるホスト A から出たログは必ず一つの fluentd に全て送られる必要があります。こういう時に、ホスト名をタグの suffix につけて hash-forward すると、予め決めた何台かの fluentd に、タグ名のハッシュを使ってほぼ均等に分散してくれます。
ちなみにハッシュアルゴリズムには murmurhash を使ってます。適当にベンチしてみたら最も均等にばらけました。まぁベンチがおかしい可能性も多いにありますが。。。
ちなみに自分で書いといて hash-forward はあんま使い道ないかもと思ってます。ホスト側は一台の fluentd にしか送らないようにして、そこでカウントもしちゃえばいいかなと。
よくありそうな config のパターン
出力元でタグの suffix にホスト名をつけてあげるとして(fluent-agent-lite なら数行のパッチでいけます)、こんな感じの定義がログの種類毎に並ぶのかなという例。酔っぱらいながら書いたので間違ってたら直しますので言ってくだしあ!
<match raw.game1.accesslog.**> # 生データをパースして構造化
type parser
remove_prefix raw
key_name message
</match>
<match game1.accesslog.**>
type copy
<store>
type groupcounter # srcipでグループカウント
group_by_keys srcip
count_interval 60s
aggregate tag
output_per_tag yes
tag_prefix srciptcount
</store>
</match>
<match srcipcount.game1.accesslog.**>
type copy
<store>
type notifier # グループカウントの結果に対して閾値超えたら通知
default_tag_warn warn.srcipcount.game1.accesslog
default_tag_crit crit.srcipcount.game1.accesslog
input_tag_remove_prefix srcipcount.game1.accesslog
<def>
check numeric_upward
warn_threshold 10
crit_threshold 20
target_key_pattern ^.+_count$
pattern srcipcount.game1.accesslog
</def>
</store>
<store>
type growthforecast # グループカウントの結果をgrowthforecastへ
remove_prefix srcipcount.game1.accesslog
gfapi_url http://localhost:5000
service srcipcount.game1.accesslog
tag_for section
name_key_pattern .+
</store>
<store>
type mongo # グループカウントの結果をmongodbへ
host localhost
flush_interval 1s
remove_tag_prefix srcipcount.game1.accesslog.
database srcipcount_game1_accesslog
tag_mapped
capped
capped_size 100m
</store>
</match>
<match warn.srcipcount.game1.accesslog> # warnの通知先
type copy
<store>
type ikachan
host localhost
port 4979
channel game1-warn
message [%s][%s]%s: %s
out_keys pattern,target_tag,target_key,value
</store>
<store>
type mail
host localhost
from warn@example.com
to warn@example.com
subject [%s][%s]
subject_out_keys pattern,target_tag
out_keys pattern,message_time,target_tag,target_key,value
</store>
</match>
<match crit.srcipcount.game1.accesslog> # critの通知先
type copy
<store>
type ikachan
host localhost
port 4979
channel game1-crit
message [%s][%s]%s: %s
out_keys pattern,target_tag,target_key,value
</store>
<store>
type mail
host localhost
from crit@example.com
to crit@example.com
subject [%s][%s]
subject_out_keys pattern,target_tag
out_keys pattern,message_time,target_tag,target_key,value
</store>
</match>
というわけで、みなさん fluentd を楽しみましょう!