Ruby 对象抛出时如何查看调用栈
How to view the call stack when an object is thrown in Ruby
监狱长 gem 使用 throw
和 catch
函数来处理控制流。这使得调试身份验证系统变得非常困难,尤其是在 devise
中,其中 gem throw
是 :warden
符号和 warden
gem catch
是的。
在我的程序中,我有一个函数(间接地)抛出一个 :warden
符号,但我不知道 throw
函数的确切调用位置是什么。有办法找到吗?
TracePoint
class 好像只支持 raise
事件。
我能够使用 TracePoint
和 throw
通过捕获 c_call
:
是一个 c 语言例程这一事实
TracePoint.new(:c_call) do |trace|
if trace.method_id == :throw
p [trace.path, trace.lineno]
end
end
这只会让您知道调用 throw
的实际位置,而不是调用到该点的所有内容的完整堆栈跟踪,尽管您也可以尝试捕捉 :call
, 并将可捕获更多信息的内容放在一起。举个简单的例子:
TracePoint.new(:call, :c_call) do |trace|
if trace.event == :call || trace.method_id == :throw
p [trace.method_id, trace.path, trace.lineno]
end
trace.disable if trace.method_id == :throw
end
完整示例:
# might_throw_cont.rb
def might_throw_second
throw :warden if rand(100) < 10
might_throw_third
end
def might_throw_third
throw :warden if rand(100) < 10
might_throw_final
end
# example.rb
require './might_throw_cont'
def might_throw_first
throw :warden if rand(100) < 10
might_throw_second
end
def might_throw_final
throw :warden if rand(100) < 10
will_throw
end
def will_throw
throw :warden
end
TracePoint.new(:call, :c_call) do |trace|
if trace.event == :call || trace.method_id == :throw
p [trace.method_id, trace.path, trace.lineno]
end
trace.disable if trace.method_id == :throw
end.enable do
catch :warden do
might_throw_first
end
puts "done"
end
显然,在这个例子中很难判断哪个方法实际抛出了符号。但是 运行 这个例子,我可以在输出中看到几次(运行 2 个例子):
# run 1
[:might_throw_first, "example.rb", 3]
[:might_throw_second, "/Users/simplelime/Documents/Ruby/might_throw_cont.rb", 1]
[:might_throw_third, "/Users/simplelime/Documents/Ruby/might_throw_cont.rb", 7]
[:might_throw_final, "example.rb", 9]
[:will_throw, "example.rb", 15]
[:throw, "example.rb", 16] # < only line you'll see if you trace only :c_call
done
# run 2
[:might_throw_first, "example.rb", 3]
[:throw, "example.rb", 4] # < only line you'll see if you trace only :c_call
done
监狱长 gem 使用 throw
和 catch
函数来处理控制流。这使得调试身份验证系统变得非常困难,尤其是在 devise
中,其中 gem throw
是 :warden
符号和 warden
gem catch
是的。
在我的程序中,我有一个函数(间接地)抛出一个 :warden
符号,但我不知道 throw
函数的确切调用位置是什么。有办法找到吗?
TracePoint
class 好像只支持 raise
事件。
我能够使用 TracePoint
和 throw
通过捕获 c_call
:
TracePoint.new(:c_call) do |trace|
if trace.method_id == :throw
p [trace.path, trace.lineno]
end
end
这只会让您知道调用 throw
的实际位置,而不是调用到该点的所有内容的完整堆栈跟踪,尽管您也可以尝试捕捉 :call
, 并将可捕获更多信息的内容放在一起。举个简单的例子:
TracePoint.new(:call, :c_call) do |trace|
if trace.event == :call || trace.method_id == :throw
p [trace.method_id, trace.path, trace.lineno]
end
trace.disable if trace.method_id == :throw
end
完整示例:
# might_throw_cont.rb
def might_throw_second
throw :warden if rand(100) < 10
might_throw_third
end
def might_throw_third
throw :warden if rand(100) < 10
might_throw_final
end
# example.rb
require './might_throw_cont'
def might_throw_first
throw :warden if rand(100) < 10
might_throw_second
end
def might_throw_final
throw :warden if rand(100) < 10
will_throw
end
def will_throw
throw :warden
end
TracePoint.new(:call, :c_call) do |trace|
if trace.event == :call || trace.method_id == :throw
p [trace.method_id, trace.path, trace.lineno]
end
trace.disable if trace.method_id == :throw
end.enable do
catch :warden do
might_throw_first
end
puts "done"
end
显然,在这个例子中很难判断哪个方法实际抛出了符号。但是 运行 这个例子,我可以在输出中看到几次(运行 2 个例子):
# run 1
[:might_throw_first, "example.rb", 3]
[:might_throw_second, "/Users/simplelime/Documents/Ruby/might_throw_cont.rb", 1]
[:might_throw_third, "/Users/simplelime/Documents/Ruby/might_throw_cont.rb", 7]
[:might_throw_final, "example.rb", 9]
[:will_throw, "example.rb", 15]
[:throw, "example.rb", 16] # < only line you'll see if you trace only :c_call
done
# run 2
[:might_throw_first, "example.rb", 3]
[:throw, "example.rb", 4] # < only line you'll see if you trace only :c_call
done