ログファイルを監視してslackに通知する

仕事で使った

準備

通知用にincoming webhookの設定をする

↓のURLからURLを発行する

api.slack.com

通知用のrubyスクリプト

※4/21追記

いろいろ勘違い等があり、紆余曲折あって↓のように変更した

nanka.hateblo.jp –ここまで

使用したrubyのバージョン

$ ruby -v
ruby 2.0.0p648 (2015-12-16 revision 53161) [x86_64-linux]
require 'net/http'
require 'uri'
require 'json'

uri = URI.parse("https://hooks.slack.com/services/*/*/*")

text = ARGV[3]

if File.pipe?(STDIN) || File.select([STDIN], [], [], 0) != nil then
  text ||= STDIN.read
end

exit unless text

payload = {
  text: text,
  channel: ARGV[0],
  username: ARGV[1],
  icon_emoji: ARGV[2]
}

Net::HTTP.post_form(uri, { payload: payload.to_json })

こんな感じで使える

ruby slack.rb "#room" "name" ":ghost:" "hoge"
echo "hoge" | ruby slack.rb "#room" "name" ":emoji:"

tail,grepと組み合わせて特定のログが書き込まれた際にslackに通知

ワンライナーにしてtmux上で動かしている

tail -n 0 -F logfile | grep --line-buffered "hoge" | while read i; do ruby slack.rb "#room" "name" ":emoji:" "$i"; done

tailの挙動がよくわからずに、ここまで作るのに結構時間がかかってしまった

以下はいくつかハマった?ポイント

監視対象が毎日貼り変わるシンボリックリンクだった

当初 tail -f しか知らなかったので、貼り変わった時どうしようか少し悩んでしまった

-F オプションにすることで、リネームされたときやシンボリックリンクが貼り変わった時でも自動で追従してくれる(らしい)

grepした結果が通知されない

tail -n 0 -F logfile | grep "hoge" | while read i; do ruby slack.rb "#room" "name" ":emoji:" "$i"; done

としてると全然通知されなかった

grep--line-buffered オプションを付けることで問題は解決した

どうやら出力バッファリングという機能が邪魔をしていたらしい

tail -Fの結果をパイプで渡すとruby側で上手に捌けない..?

tail -Fが特殊な挙動をすることが原因だと思いこんでいるが、

tail -F logfile | ruby slack.rb "#room" "name" ":emoji:"

とすると、どこかのタイミングで標準入力がない状態で↓のif文が通ってしまい、STDIN.readでキーボード入力待ちになってしまう場合がある

if File.pipe?(STDIN) || File.select([STDIN], [], [], 0) != nil then
  text ||= STDIN.read
end

そこで while read i で一度受け取るようにしたら、正しく動くようになった

tail -F logfile | while read i; do ruby slack.rb "#room" "name" ":emoji:" "$i"; done

原因がわからないのが気持ち悪い、いつかtailの実装を読んでみたい

※4/21追記

原因については↓

nanka.hateblo.jp –ここまで