続・fluentdでつくる監視系

[fluentdでつくる監視系 - Qiita](http://qiita.com/kotatsu360/items/2985056d5af72c6eb5c2)の続き

いつもアプリケーションの開発ばかりで、まじめに監視系を考えたことがなかったので、
fluentdを中心にした監視系を作ってみた。

# 前提（変更なし）

1. 複数台のアプリケーションサーバ
1. 一台のログ収集サーバ
1. ログにはエラーログとアクセスログの大きく2種類を用意する
1. エラーログは更に複数のレベルでファイル単位にわかれている
   1. fatal
   1. error
   1. warn
1. アプリケーションサーバとログ収集サーバは同一ネットワーク上にある

# やりたいこと

メールで来ても絶対に気がつかない自信がある。
異常の側から教えてくれる仕組みを目指す。

1. fatalログが出た場合は、電話による通知を行う
1. 全てのエラーログはchatツールに出力する
1. ログのバックアップ
1. ログの分析・可視化

1,2,3については[fluentdでつくる監視系 - Qiita](http://qiita.com/kotatsu360/items/2985056d5af72c6eb5c2)にまとめた。
この記事では前回積み残していた課題を解決する

# 今回解決するもの

1. チャットツールやTwilioへ任意のメッセージを渡す
1. 設定をDRYにする

# 記述変更

## ログの送信側
特に何もしない

## ログの受信側

```bash
$ /opt/td-agent/embedded/bin/fluentd --version
fluentd 0.12.8
# filterを使うので0.12以上である事を確認
```

/etc/td-agent/td-agent.conf

```apache
<source>
  type forward
  port 24224
</source>

<filter app.{warn,error}>
  type record_transformer
  enable_ruby
  <record>
     hipchat_message "${tag} status:${res[\"statusCode\"]}\n${error}"
  </record>
</filter>
<filter app.fatal>
  type record_transformer
  enable_ruby
  <record>
    message "fatalエラーが発生しました。" #twilio用
    hipchat_message "@all ${tag} status:${res[\"statusCode\"]}\n${error}"
  </record>
</filter>

<match app.*>
  type forest
  subtype copy
  <template>
    <store>
      type s3
      aws_key_id "#{ENV['AWS_ACCESS_KEY_ID']}"
      aws_sec_key "#{ENV['AWS_SECRET_KEY']}"
      s3_bucket <AWS S3 BUCKET NAME>
      s3_region ap-northeast-1
      path ${tag_parts[0]}/${tag_parts[1]}/ # app/access/, app/fatal/, app/error/, ...
      buffer_path /var/log/td-agent/buffer/s3_${tag_parts[0]}_${tag_parts[1]}
      time_slice_format %Y-%m-%d/%H
      time_slice_wait 10m
    </store>
  </template>
  <case app.{warn,error}>
    <store>
      type hipchat
      api_token "#{ENV['HIPCHAT_API_TOKEN']}"
      default_room <YOUR CHAT ROOM>
      default_from fluentd
      default_color yellow
      default_notify 1
      default_format text  # メンションを含めたい場合はtextである必要がある。HipChatのAPI仕様
      default_timeout 3
      key_name hipchat_message  # errorから変更
    </store>
  </case>
  <case app.fatal>
    <store>
      type hipchat
      api_token "#{ENV['HIPCHAT_API_TOKEN']}"
      default_room <YOUR CHAT ROOM>
      default_from fluentd
      default_color red         # メッセージカラーを危険そうな赤に変更
      default_notify 1
      default_format text
      default_timeout 3
      key_name hipchat_message
    </store>
    <store>
     type twilio
     account_sid    "#{ENV['TWILIO_ACCOUNT_SID']}"
     auth_token     "#{ENV['TWILIO_AUTH_TOKEN']}"
     from_number    +810000000000                # twilioで取得した番号
     default_number +811111111111, +812222222222 # 電話を受け取りたい番号
    </store>
  </case>
</match>

<match fluent.**>
  type stdout # fluentd自体のログは/var/log/td-agent/td-agent.logへ
</match>
```

### filter, type record_transformer
0.12以降で追加されたfilterを使ってhipchat用メッセージとtwilio用メッセージを追加した。
0.12より前のバージョンの場合は、[fluent-plugin-record-reformer](https://github.com/sonots/fluent-plugin-record-reformer)などのoutput_pluginで操作するのがセオリーなよう。

app.fatalがこういうログなら

```json
{"req":{"method":"GET","url":"/"},"res":{"statusCode":500}, "error":"hogehoge"}
```

こうなる。

```json
{"req":{"method":"GET","url":"/"},"res":{"statusCode":500},"error":"hogehoge","message":"fatalエラーが発生しました。","hipchat_message":"@all app.fatal status:500\nhogehoge"}
```

ちなみに、filterは上から何回でもマッチするよう（matchやcaseは先勝ち）。

```apache
<filter app.fatal>
</filter>
<filter app.{warn,error,fatal}>
</filter>

# fatalは両方のfilterを通る
```

### enable_ruby

${}の中でruby記法が使えるようになる。入れ子になっているJSONの中を読みたかったので設定。

```apache
   "${res[\"statusCode\"]}" # => 500
```


### 設定をDRYに
基本的には`<match app.access>`を`<match app.*>`に混ぜただけ。全ログがS3に入るようにし、
warn, errorのログはhipchatへ、fatalはhipchat+twilioへ投げる。

fatalのときだけhipchatへポストされるメッセージ色を変えたかったので、ほとんど同じ内容だけど2回書いてる。全く同じ内容で良い時は、`@include`が便利そう。

/etc/td-agent/hipchat.conf

```apache
      type hipchat
      api_token "#{ENV['HIPCHAT_API_TOKEN']}"
      default_room "#{ENV['HIPCHAT_ROOM']}"
      default_from fluentd
      default_color yellow
      default_notify 1
      default_format text
      default_timeout 3
      key_name hipchat_message
```

```apache
  <case app.{warn,error}>
    <store>
      @include ./hipchat.conf
    </store>
  </case>
```

短い。

# その他
* fluentd自体のログもとりあえずtd-agent.logに放り込んでおく。（`<match fluent.**>`）

# まとめ
チャットツールやtwilioに任意のメッセージをポストさせることができた。
重複する記述を可能な限り排除した。

# 参考
[Filter Plugin Overview | Fluentd](http://docs.fluentd.org/articles/filter-plugin-overview)
[Fluentd v0.12の目玉機能らしいFilterを試してみた - Qiita](http://qiita.com/muran001/items/f73d19398b750abb9c2d)
[Configuration File | Fluentd](http://docs.fluentd.org/articles/config-file#5-re-use-your-config-the-ldquoincluderdquo-directive)