fluentdでホスト名付きでログを受け取って解析してグラフにしたい

fluentd で Nginx などのログを解析してホスト名付きで growthforecast に POST してグラフを描いていました

しかしそのログを解析しているサーバーは AP サーバーでユーザーからのリクエストを処理しています
なのでログファイルを正規表現で parse する fluentd の処理は CPU を消費していました

そこで各 AP サーバーから fluentd でログを parse せずにそのまま他のサーバーに送信してそのサーバーがログの parse と growthforecast へ POST するようにしようと考えました
その時に各ホストは今まで通り別にグラフを描こうと思ったのですが想像以上に苦戦したので書いてみます

fluentd はほぼ初めてなので間違っているところやおかしなところがあればぜひ指摘して欲しいです


## fluentd で parse せずに forward する

fluentd の in_tail プラグインでは `format none` にすればログを正規表現で parse しないでそのまま読み込むことができます

また forward プラグインだとホスト名が付与されないので以下のファイルを plugin ディレクトリに入れて forward_with_hostname プラグインを使えるようにしましょう

  * [Forwardプラグインで投げるときにホスト名を追加する](https://gist.github.com/harukasan/4681483)

```access_log_forward.conf
<source>
  type tail
  tag ap_front.access.service
  path /var/log/nginx/access.log
  pos_file /var/log/nginx/access.log.pos
  format none
</source>

<match ap_front.access.service>
  type forward_with_hostname
  flush_interval 1s

  buffer_type file
  buffer_path /var/tmp/fluentd/buffer/ap.activity.*.buffer
  buffer_chunk_limit 2m
  buffer_queue_limit 128

  <server>
    name admin
    host admin
  </server>
</match>
```

こんな感じにすると admin ホストにログを parse せずそのまま送ることができます

これで message キーにログが一行入って host キーにホスト名が入った状態でログを受け取ることができます

またこのような使い方の場合 fluent-agent-lite の方が軽くていいと思うのでこちらにいずれ乗り換えるかもしれません

  * [fluent-agent-lite と td-agent で、小さくはじめる fluentd - Studio3104::BLOG.new](http://studio3104.hatenablog.com/entry/20120824/1345795228)

## 受け取ったサーバーでログを解析する

ログを受け取れるようになったのでここから処理を書いていきます

忘れてはいけないのはホスト名を最終的に growthforecast に投げるので最後まで保持しなければならない点です
ここは fluentd ではタグ名にする方法が一番簡単なのでそういう方針で行きます

まずなにはともあれログを解析します

  * [tagomoris/fluent-plugin-parser](https://github.com/tagomoris/fluent-plugin-parser)

を使います

デバッグのためにあらかじめ設定の最後に以下を書いておきます

```fluentd.conf
<match **>
  type stdout
</match>
```

こうしておけば match しなかったものはすべて標準出力に出力されます


```access_log_parse.conf
<source>
  type forward
</source>
<match ap_front.access.service>>
  type parser
  tag src.service.access
  format ltsv
  key_name message
  reserve_data yes
</match>
```

format には正規表現か ltsv などが書けます
ログ自体はデフォルトだと message キーに格納されているので `key_name message` を指定します

またここで重要なのは `reserve_data yes` という指定です
このままだと parse した結果だけが引き継がれるので折角送ったホスト名が脱落してしまいます
`reserve_data yes` を指定すると parse される前の元データもそのまま引き継がれます
なのでホスト名はそのまま host キーに入った状態で引き継がれます


### 条件でタグを書き換える

fluentd でデータを引き継ぐのはタグでやるのが一番簡単です

そこでホスト名をタグに含めます

  * [fluent/fluent-plugin-rewrite-tag-filter](https://github.com/fluent/fluent-plugin-rewrite-tag-filter)

rewrite_tag_filter プラグインを使ってタグを書き換えます

```rewrite_tag.conf
<match src.service.access>
  type rewrite_tag_filter
  remove_tag_prefix src
  rewriterule1 host (.+) ${tag}.$1
</match>
```

`${tag}` で現在のタグが取得できます
なので今回の場合，ホスト名が host ならタグが `service.access.host` に書き換えられます


### データを解析する

ログから今回グラフにしたいデータを取得します

  * [FluentdとGrowthForecastを使った可視化 〜 Haikanko OSS化への道(4) - sonots:blog](http://blog.livedoor.jp/sonots/archives/25189820.html)

これを参考にステータスコードとレスポンスタイムを取得します


```analytics.conf
<match service.access.*>
  type copy

  <store>
    type numeric_monitor
    count_interval 60
    aggregate tag
    output_per_tag yes
    tag_prefix monitor
    monitor_key request_time
    output_key_prefix response_time
    percentiles 99
  </store>

  <store>
    type datacounter
    count_interval 60
    aggregate tag
    output_per_tag yes
    tag_prefix count
    outcast_unmatched true
    count_key status
    pattern1 200 ^200$
    pattern2 304 ^304$
    pattern3 403 ^403$
    pattern4 404 ^404$
    pattern4 499 ^499$
    pattern5 500 ^500$
    pattern6 504 ^504$
    pattern7 5xx ^5\d\d$
  </store>

</match>
```

それぞれのプラグインの使い方は以下を参考にしてください

  * [tagomoris/fluent-plugin-numeric-monitor](https://github.com/tagomoris/fluent-plugin-numeric-monitor)
  * [tagomoris/fluent-plugin-datacounter](https://github.com/tagomoris/fluent-plugin-datacounter)

基本的にタグを書き換えるような機能は各プラグインに依存しています
大体のプラグインには prefix を付けるなどの機能には対応していますが，自由に書き換えたい場合は先程紹介した rewrite_tag_filter などそれ専用のプラグインに頼る必要があります
今回のようにホスト名をタグに付けたいという場合は事前にタグ名にホスト名を付与することが重要です


### growthforecast に POST する

growthforecast に POST するために以下のプラグインを使います

  * [tagomoris/fluent-plugin-growthforecast](https://github.com/tagomoris/fluent-plugin-growthforecast)

この際にタグ名からホスト名を取得する必要があるので今回は forest プラグインと組み合わせてみます

  * [tagomoris/fluent-plugin-forest](https://github.com/tagomoris/fluent-plugin-forest)

```growthforecast.conf
<match monitor.service.access.*>
  type forest
  subtype growthforecast
  <template>
    gfapi_url http://localhost:5125/api/
    graph_path service/${tag_parts[-1]}/${key_name}
    name_key_pattern .
    enable_float_number true
  </template>
</match>

<match count.service.access.*>
  type forest
  subtype growthforecast
  <template>
    gfapi_url http://localhost:5125/api/
    graph_path service/${tag_parts[-1]}/${key_name}
    name_key_pattern .
    enable_float_number true
  </template>
</match>
```

forest プラグインを使うと `${tag_parts[-1]}` のようにタグの一部を簡単に呼び出すことができます


### まとめ

fluentd は様々なプラグインを組み合わせることで柔軟な設定が可能ですが，どのプラグインをどのように組み合わせればいいのかが場合によっては煩雑になります

fluentd で情報を引き継ぐのはタグくらいしかないのでタグにどういうデータを載せるのか考えて一つ一つ整理して確認しながら書いていきましょう

[Fluentdの設定を考えるときはこんなかんじで考えると便利 - Qiita](http://qiita.com/harukasan/items/0e69f5c17f12db7b2e98)