MAGAZINE

ルーターマガジン

Ruby

[運用初心者必見] これだけやれば安心、たった3行でRubyからSlackエラー通知

2019.10.30
Pocket

こんにちは、エンジニアの大壁です。
運用の段階ではプロセスが停止しないように、あるいは停止してもすぐ気付けるように気を配る必要があります。
慣れないうちは中々難しく、一日中サーバーに張り付いている訳にもいかずお困りの方も居ますでしょう。
そこで今回はたった3行でエラーを通知する方法を紹介します。

前提

今回はslackに通知する前提で進めます。
もちろんメールやLINEでの通知でも可能ですので、お好みの通知方法に置き換えて下さい。

以下は'slack-notifier'というgemを使用したサンプルコードです。
引数にテキストを渡すと指定したチャンネルに投稿してくれます。

require 'slack-notifier'

def error_notify(text)
  url = "https://hooks.slack.com/services/xxxxxxxxxxxxxxxxxx/xxxxxxxxxxxxxxxxxxxxxxxx" # ←チャンネルのWebhook URL
  slack = Slack::Notifier.new url, username: 'Error Notifier'
  slack.post text: "#{text}"
end

begin ~ rescueは使いたくない

まず思いつくのがbegin ~ rescueですが、以下のようにrescue節内で通知メソッドを呼び出せば事足ります。

begin
  some_function
rescue
  error_notify("エラーです")
end

しかしシステムが大きくなってくるとbegin ~ rescue節が増えてくるので、全てに通知メソッドを書き加える必要があります。
書き加えた分だけテストの回数も増えるので大変です。
これを回避するために、プロセスの終了をトリガーとして通知が行われるようにします。
処理を一箇所にまとめることができて、メンテナンスが容易になります。

プロセス終了時に処理を発生させる

at_exitブロックを使用するとプロセスの終了時に中の処理が実行されます。

at_exit do
  puts "終了しました"
end

ここにお好みの通知メソッドを書いておくと、終了時に通知が来るようになります。
ただし、このままでは正常終了時にも通知が来ますのでもう一工夫必要です。

$!と$@

$!と$@には最後に発生したエラー情報が格納されています。

$!: 最後に発生したエラー  
$@: 最後に発生したエラーのバックトレース  

正常終了時にはどちらもnilになりますので、$!がnilの時は通知しないように条件分岐してあげれば良いです。

サンプルコード

以上の前置きを踏まえて、以下のサンプルコードを作成しました。
これをプログラムの最初の方にコピペしてください。

at_exit do
  error_notify("#{$!.class}\n#{$@[0]}") unless $!.class == NilClass
end

まずerror_notify("#{$!.class}\n#{$@[0]}")ですが、エラーのクラスとバックトレースの一行目をslackに通知しています。
この組み合わせが必要充分でして、ファイル名とエラーのクラスを見れば何が起きたか分かるからです。
より詳細なログはサーバー内に出力しておきましょう!

またunless $!.class == NilClassで正常終了時には通知しないように分岐させています。
エラーのクラスによって通知する・しないを切り替えられますので、「StandardErrorの時のみ通知する」などカスタマイズできます。
私はInterrupt(ctrl + cで止めた場合)とSignalException(pkillで止めた場合)なども通知しないようにしています。

終わりに

いかがだったでしょうか?
新人なのに運用を任されたあなた!!
よく止まるシステムを運用しているあなた!!
安定かつ省エネの運用ライフを送りましょう!!

Pocket

CONTACT

お問い合わせ・ご依頼はこちらから