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を楽しみましょう!