BLOGTIMES
2009/05/09

予期しない例外でRubyが落ちたときのログを取る

  ruby 
このエントリーをはてなブックマークに追加

最近、Rubyでバッチを書いているのですが、予期しないエラーでスクリプトが落ちるとスタックトレースがコンソールにだけ出力されてしまうという現象にちょっと頭を悩ませていました。自分だけがバッチを起動させるなら標準出力をファイルにリダイレクトしておけばいいのですが、自分がさわらないときにだけ落ちるという謎な挙動なのです。

ということで、Rubyの終了処理の部分に何かフックのようなものがないのかなと探してみたらRubyの終了処理のフックはいろいろ種類があるようです。

終了処理 - Rubyリファレンスマニュアル」より

 1. すべてのスレッドを Thread.kill
 2. Ruby の疑似シグナル SIGEXIT のハンドラが登録されていればそれを実行
 3. END ブロック(END { ... } または関数 at_exit で指定したブロック)が登録されていれば、 そのブロックを登録とは逆順に実行
 4. ObjectSpace.define_finalizer により、ファイナ ライザが登録されていればそれらを実行(順序不定)
 5. exit(3) により終了

今回のパターンであれば、2の疑似シグナル(SIGEXIT)に対するハンドラを登録するか、3のENDもしくはat_exitによるブロックを登録するかいずれかの方法が良さそうです。

サンプルコード

コードを書くとすればこんな感じでしょうか。

fatallogtest.rb

#!/usr/bin/ruby STDOUT.reopen "/dev/null" STDERR.reopen "/dev/null" require 'logger' logger = Logger.new('app.log') Signal.trap(:EXIT){ logger.fatal($!) if $! } raise "hoge"

実行すると、標準出力と標準エラーを捨てているので、画面には何も表示されませんが下記のようにログにはエラーの内容が記録されています。

app.log

# Logfile created on Sat May 9 22:32:20 +0900 2009 by logger.rb/1.5.2.9 F, [2009-05-09T22:32:20.152512 #20121] FATAL -- : hoge (RuntimeError) test.rb:13

ただ、この実装だとexit()を使ったときにもexit (SystemExit)のようなログが残ってしまうので、本当に例外だけを拾うには$!の内容をもう少しチェックする必要がありそうです。僕は気にしないという解決方法をとってしまいましたけど。


    トラックバックについて
    Trackback URL:
    お気軽にどうぞ。トラックバック前にポリシーをお読みください。[policy]
    このエントリへのTrackbackにはこのURLが必要です→https://blog.cles.jp/item/3034
    Trackbacks
    このエントリにトラックバックはありません
    Comments
    愛のあるツッコミをお気軽にどうぞ。[policy]
    古いエントリについてはコメント制御しているため、即時に反映されないことがあります。
    コメントはありません
    Comments Form

    コメントは承認後の表示となります。
    OpenIDでログインすると、即時に公開されます。

    OpenID を使ってログインすることができます。

    Identity URL: Yahoo! JAPAN IDでログイン