エラーログをSlack通知する

環境

  • CentOS Linux release 7.1.1503 (Core)
  • td-agent: 0.12.12
  • Nginx: 1.8.0

概要

社内でSlackによる連携が進み
ログ管理もfluentdにまとめつつあるので
エラーログで何かあったらSlack通知させようと思いチャレンジ♪

以下のような流れを想定しています。

Nginx error.log —> fluentd —> slack

gemでも作るか!と思ったら既にSlack Pluginは豊富なので
あやからせていただきます!

準備

fluentdが/var/log/nginx/error.log にアクセスできるようにしておいてください。

ログがtailできないなんてときは以下参照♪

利用するfluentd Plugin

td-agent.conf設定

error.logフォーマット設定

  • Nginxのエラーログが以下のようにフォーマットされ出力されているとします。
1
2015/11/18 18:01:47 [error] 23029#0: *9086 open() "/var/golang/src/img/tmp.png" failed (2: No such file or directory), client: ***.**.**.****, server: hogehoge.jp, request: "GET /img/tmp.png HTTP/2.0", host: "hogehoge.jp", referrer: "http://hogehoge.jp"
  • fluentdのformat設定
1
format /^(?<time>.+) \[(?<level>[^\]]+)\] *(?<message>.*)$/

上記fomat設定によって以下のように key : value 構成で取得できます。

1
2
3
time : 2015/11/18 18:01
level : error
message : or] 23029#0: *9086 open() "/var/www/html/img/tmp.png" failed (2: No such file or directory), client: ***.**.**.****, server: hogehoge.jp, request: "GET /img/tmp.png HTTP/2.0", host: "hogehoge.jp", referrer: "http://hogehoge.jp"

設定によってはうまく通知させずハマりました汗

tag名をリライト

上記 で取得した key:value を元に tagを書き換えます。

以下の例だと、
levelerror の場合、 slack.error.${tag} (slack.error.nginx.error) にタグを書き換えてます。
他、warn, fatal も同様です。

1
2
3
4
5
6
<match nginx.error>
type rewrite_tag_filter
rewriterule1 level error slack.error.${tag}
rewriterule2 level warn slack.warn.${tag}
rewriterule3 level fatal slack.fatal.${tag}
</match>

また message で取得した値の中に

特定文字列が含まれている場合等も可能です。

例) message に 「PHP Fatal Error」 で始まる文字列が含まれている場合にslack.fatal.${tag}に書き換える。

1
2
3
4
5
6
7
8
<match nginx.error>
type rewrite_tag_filter
rewriterule1 level error slack.error.${tag}
rewriterule2 level warn slack.warn.${tag}
rewriterule3 level fatal slack.fatal.${tag}

rewriterule4 message ^PHP Fatal Error.*$ slack.fatal.${fatal} # 追加
</match>

フィールド追加

  • source_id 追加

time, level, message 以外に source_id を追加してます。
以下の例では source_id` に tag_suffix[1] を指定しています。

1
2
3
4
5
6
7
<match slack.**>
type record_reformer
tag reformed.${tag}
<record>
source_id ${tag_suffix[1]}
</record>
</match>

tag_suffix について

tag が reformed.slack.error.nginx.error とすると
以下のような仕様です。

1
2
3
4
5
6
tag_suffix[0] → reformed.slack.error.nginx.error
tag_suffix[1] → slack.error.nginx.error
tag_suffix[2] → error.nginx.error

tag_suffix[-1] → error
tag_suffix[-2] → nginx.error

slack通知

  • incoming WebhookからWebhookURLを設定
1
2
3
4
5
6
7
8
9
10
<match reformed.slack.**>
type slack
webhook_url https://hooks.slack.com/services/xxxxxxxxx/xxxxxxxxx/xxxxxxxxxxxxxxxxxxxxxxxx
channel flag_production
username fluentd
title_keys source_id
title %s
color danger
flush_interval 5s
</match>

通知結果

余談

Slackに通知しても休日で業務連絡を見ないということは往々にしてあるので
Twillioで電話通知するpluginもあります。

y-ken/fluent-plugin-twilio

株式会社KDDIウェブコミュニケーションズが提供する有料サービスです。
比較的安価なので導入検討してみてください。

Twillio 料金表

twilio price

かつての「メール見てませんでした💦」
なんてことがなくなりそうなのは良いですね

以上です。

3分で出来る! AWS EC2(CentOS7)に td-agent2インストール

環境

  • AWS EC2
  • CentOS Linux release 7.1.1503 (Core)

td-agent2 インストール

1
$ sudo curl -L http://toolbelt.treasuredata.com/sh/install-redhat-td-agent2.sh | sh

起動/サービス登録

1
2
$ sudo systemctl start td-agent
$ sudo chkconfig td-agent on

systemctl enableするとchkconfig使ってと怒られます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ sudo systemctl enable td-agent

td-agent.service is not a native service, redirecting to /sbin/chkconfig.
Executing /sbin/chkconfig td-agent on
The unit files have no [Install] section. They are not meant to be enabled
using systemctl.
Possible reasons for having this kind of units are:
1) A unit may be statically enabled by being symlinked from another unit's
.wants/ or .requires/ directory.
2) A unit's purpose may be to act as a helper for some other unit which has
a requirement dependency on it.
3) A unit may be started when needed via activation (socket, path, timer,
D-Bus, udev, scripted systemctl call, ...).
[root@ip-172-31-19-253 log]#

試験

設定ファイル (/etc/td-agent/td-agent.conf)を見ると
デフォルト設定では、
httpプロトコルport:8888からLoggingしtd-agent.log(/var/log/td-agent/td-agent.log)に流すようにしています。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# HTTP input
# POST http://localhost:8888/<tag>?json=<json>
# POST http://localhost:8888/td.myapp.login?json={"user"%3A"me"}
# @see http://docs.fluentd.org/articles/in_http
<source>
type http
port 8888
</source>

## live debugging agent
<source>
type debug_agent
bind 127.0.0.1
port 24230
</source>

以下のようにコマンドを実行してtd-agent.logを確認してみる。

1
2
3
4
5
$ curl -X POST -d 'json={"json":"TEST!!"}' http://localhost:8888/debug.test

$ sudo tail -f /var/log/td-agent/td-agent.log

2015-09-19 17:34:50 +0900 debug.test: {"json":"TEST!!"}

上記のように正しくロギングされていることが確認できました。

fluentd設定ハマった所あるある

以下随時追加。

環境

  • CentOS Linux release 7.1.1503 (Core)
  • Fluentd 0.12.12
  • Nginx 1.8.0

Permission denined

  • パーミッションエラー!
1
2
3
4
# tail -f /var/log/td-agent/td-agent.log

2015-08-19 14:17:14 +0900 [error]: Permission denied @ xxxxxxx - /var/log/nginx/error.log
2015-08-19 14:17:14 +0900 [error]: suppressed same stacktrace

対策

td-agent実行ユーザをrootに変更する。

1
2
3
4
5
6
7
$ sudo vim /etc/init.d/td-agent

- TD_AGENT_USER=td-agent
- TD_AGENT_GROUP=td-agent

+ TD_AGENT_USER=root
+ TD_AGENT_GROUP=root

デーモンリロード

1
sudo systemctl daemon-reload

動作確認

以下のようにtailが正しく実行できていることが確認できます。

1
2
3
4
# tail -f /var/log/td-agent/td-agent.log

2015-08-19 14:17:15 +0900 [info]: following tail of /var/log/nginx/access.log
2015-08-19 14:17:15 +0900 [info]: following tail of /var/log/nginx/error.log

[warn]: pattern not match

これかなりハマりました。

Nginxのlogを流すときに以下のようにfomatするように書かれている記事を多く見たので
設定してみたらエラー発生(; >_<)

  • /etc/td-agent/td-agent.conf
1
2
3
4
5
6
7
<source>
type tail
format nginx
path /var/log/nginx/access.log
pos_file /var/log/td-agent/nginx-access.pos
tag nginx.access
</source>

対策

以下のように修正

  • /etc/td-agent/td-agent.conf
1
2
3
4
5
6
7
8
<source>
type tail
format /^(?<remote>[^ ]*) (?<host>[^ ]*) (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^ ]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)" "(?<forwarder>[^\"]*)")?/
time_format %d/%b/%Y:%H:%M:%S %z
path /var/log/nginx/access.log
pos_file /var/log/td-agent/nginx-access.pos
tag nginx.access
</source>

td-agent再起動

1
$ sudo systemctl restart td-agent

これで大丈夫。

buffer_path 重複

1
[error]: failed to configure sub output redshift: Other '' plugin already use same buffer_path: type = , buffer_path = *

元々の設定は以下の様にしていました。
td-agent の送信先にトラブルがあり buffer が溜まり重複しエラーとなっていました。

1
buffer_path /logs/td-agent/nginx/logs

例)以下の様な tag があった場合、buffer_path は同じく /logs/td-agent/nginx/logs となってしまう

hogehoge.20170101.log
hogehoge.20170102.log

対策

tag_parts を用い、以下の様に tag 毎に buffer_path をユニークにすることで解決

1
buffer_path /logs/td-agent/nginx/logs_${tag_parts[0]}_${tag_parts[1]}

引き続き何か発生したら追記していきます。