いつもアプリケーションの開発ばかりで、まじめに監視系を考えたことがなかったので、
fluentdを中心にした監視系を作ってみた。
前提(変更なし)
- 複数台のアプリケーションサーバ
- 一台のログ収集サーバ
- ログにはエラーログとアクセスログの大きく2種類を用意する
- エラーログは更に複数のレベルでファイル単位にわかれている
- fatal
- error
- warn
- アプリケーションサーバとログ収集サーバは同一ネットワーク上にある
やりたいこと
メールで来ても絶対に気がつかない自信がある。
異常の側から教えてくれる仕組みを目指す。
- fatalログが出た場合は、電話による通知を行う
- 全てのエラーログはchatツールに出力する
- ログのバックアップ
- ログの分析・可視化
1,2,3についてはfluentdでつくる監視系 - Qiitaにまとめた。
この記事では前回積み残していた課題を解決する
今回解決するもの
- チャットツールやTwilioへ任意のメッセージを渡す
- 設定をDRYにする
記述変更
ログの送信側
特に何もしない
ログの受信側
$ /opt/td-agent/embedded/bin/fluentd --version
fluentd 0.12.8
# filterを使うので0.12以上である事を確認
/etc/td-agent/td-agent.conf
<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などのoutput_pluginで操作するのがセオリーなよう。
app.fatalがこういうログなら
{"req":{"method":"GET","url":"/"},"res":{"statusCode":500}, "error":"hogehoge"}
こうなる。
{"req":{"method":"GET","url":"/"},"res":{"statusCode":500},"error":"hogehoge","message":"fatalエラーが発生しました。","hipchat_message":"@all app.fatal status:500\nhogehoge"}
ちなみに、filterは上から何回でもマッチするよう(matchやcaseは先勝ち)。
<filter app.fatal>
</filter>
<filter app.{warn,error,fatal}>
</filter>
# fatalは両方のfilterを通る
enable_ruby
${}の中でruby記法が使えるようになる。入れ子になっているJSONの中を読みたかったので設定。
"${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
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
<case app.{warn,error}>
<store>
@include ./hipchat.conf
</store>
</case>
短い。
その他
- fluentd自体のログもとりあえずtd-agent.logに放り込んでおく。(
<match fluent.**>
)
まとめ
チャットツールやtwilioに任意のメッセージをポストさせることができた。
重複する記述を可能な限り排除した。
参考
Filter Plugin Overview | Fluentd
Fluentd v0.12の目玉機能らしいFilterを試してみた - Qiita
Configuration File | Fluentd