LoginSignup
4
3

More than 5 years have passed since last update.

mruby で例外が起こった場所の backtrace を rescue 節など他の場所でも取得できるようにする

Last updated at Posted at 2015-04-19

追記 (2016/01/11)

現在の mruby の master の挙動がここで書いている対策が必要ないような動作になっているため、
この記事に書いてある様なことをする必要はなくなっているかと思います。

本文

mruby で以下の様なコードを実行すると

def g
  raise "test"
end

def f
  begin
    g
  rescue => e
    raise e
  end
end

begin
  f
rescue => e
  puts "e.backtrace"
  puts "#{e.backtrace.map{|v| "  " + v}.join("\n")}"
end


以下のように出力されます。

e.backtrace
  exception_default.rb:18

backtrace を出力するところの rescue 節の中を指し示しています。

rubyだと以下のように出力されます。

e.backtrace
  exception_default.rb:3:in `g'
  exception_default.rb:8:in `f'
  exception_default.rb:15:in `<main>'

以下を見ると現状の mruby の挙動のようです。

https://github.com/mruby/mruby/issues/1661
http://qiita.com/seanchas_t/items/ca293f9dd4454cd6cb6d

デバッグ時などは ruby の挙動のほうが
例外が起こった場所がわかりやすいので
mruby本体は書き換えずにrubyのような出力が
出来る方法を考えました。
以下の処理を追加すると、
mruby での backtrace が ruby と同じようなものになります。

class Exception

  alias_method :old_initialize, :initialize 
  alias_method :old_backtrace, :backtrace 

  @@initializing = false
  @@current_backtrace = nil

  def initialize(*args)
    old_initialize(*args)

    unless @@initializing
      # not thread safe
      @@initializing = true
      begin
        raise ""
      rescue => e
        @stored_backtrace = e.backtrace[2..-1]
      end
      @@initializing = false
    else

    end
  end

  def backtrace
    if @stored_backtrace
      @stored_backtrace
    else
      self.old_backtrace
    end
  end
end

先ほどのコードの先頭にこのコードを挿入すると、mrubyでの出力は以下のようになります。

e.backtrace
  exception_better_backtrace.rb:37:in Object.g
  exception_better_backtrace.rb:42:in Object.f
  exception_better_backtrace.rb:49

コード及び確認用コードは以下においてあります。

追記 (2015/11/29)

mrbgems を作りました。
https://github.com/dycoon/mruby-ruby-like-backtrace

4
3
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3