How do you view a sample of the call stack in ruby?
Just put
puts caller
anywhere in the code. If you don't like its format, it's an array of strings, so you can do some regex manipulation for a desired output.
How to view the call stack when an object is thrown in Ruby
I was able to get something working using TracePoint
and the fact that throw
is a c language routine by trapping c_call
:
TracePoint.new(:c_call) do |trace|
if trace.method_id == :throw
p [trace.path, trace.lineno]
end
end
This will only get you where the call to throw
was actually made, not a full stack trace of everything called up to that point, though you could play around with catching :call
as well, and put something together that captures more information. As a quick example:
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
Full example:
# 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
Obviously, going to be hard to tell which method actually threw the symbol in this example. But running the example, a couple times I'll be able to see in the output (2 example runs):
# 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
Call stack around ruby code
It's not exactly like that, but it's very similar.
You can use method method
. For example
2.method(:hours)
=> #<Method: Fixnum(Numeric)#hours>
or probably more detail
2.method(:hours).source_location
=> ["~/.rvm/gems/ruby-2.3.3/gems/activesupport-4.2.7.1/lib/active_support/core_ext/numeric/time.rb", 29]
and after that you can use debuger(if posible) or go deeper
Another detail in this answer How to find where a method is defined at runtime?
Get current stack trace in Ruby without raising an exception
You can use Kernel#caller
:
# /tmp/caller.rb
def foo
puts caller # Kernel#caller returns an array of strings
end
def bar
foo
end
def baz
bar
end
baz
Output:
caller.rb:8:in `bar'
caller.rb:12:in `baz'
caller.rb:15:in `<main>'
how to get/traceback method calls stack
Ruby has one stdlib called Tracer
. I would demonstrate it with a small example s below :
require 'tracer'
Tracer.on
def a;end
def b; a ; end
def c; b ; end
c
Tracer.off
Let me now run the code :
(arup~>test)$ ruby -v c.rb
ruby 2.0.0p0 (2013-02-24 revision 39474) [i686-linux]
#0:c.rb:4::-: def a;end
#0:c.rb:5::-: def b; a ; end
#0:c.rb:6::-: def c; b ; end
#0:c.rb:7::-: c
#0:c.rb:6:Object:>: def c; b ; end
#0:c.rb:6:Object:-: def c; b ; end
#0:c.rb:5:Object:>: def b; a ; end
#0:c.rb:5:Object:-: def b; a ; end
#0:c.rb:4:Object:>: def a;end
#0:c.rb:4:Object:<: def a;end
#0:c.rb:5:Object:<: def b; a ; end
#0:c.rb:6:Object:<: def c; b ; end
#0:c.rb:8::-: Tracer.off
(arup~>test)$
Description of some symbolic notations here came in the output:
- +>+ - call a Ruby method
- - - execute code on a new line
- +<+ - return from a Ruby method
Pry: show me the stack
Use the pry-stack_explorer plugin, it allows you to move up and down the call-stack (with up
and down
), display the callstack (with show-stack
), and so on:
see here:
Frame number: 0/64
From: /Users/johnmair/ruby/rails_projects/personal_site/app/controllers/posts_controller.rb @ line 7 PostsController#index:
5: def index
6: @posts = Post.all
=> 7: binding.pry
8: end
[1] pry(#<PostsController>)> show-stack
Showing all accessible frames in stack (65 in total):
--
=> #0 index <PostsController#index()>
#1 [method] send_action <ActionController::ImplicitRender#send_action(method, *args)>
#2 [method] process_action <AbstractController::Base#process_action(method_name, *args)>
#3 [method] process_action <ActionController::Rendering#process_action(*arg1)>
<... clipped ...>
[2] pry(#<PostsController>)> up
Frame number: 1/64
Frame type: method
From: /Users/johnmair/.rvm/gems/ruby-2.0.0-p0/gems/actionpack-3.2.8/lib/action_controller/metal/implicit_render.rb @ line 4 ActionController::ImplicitRender#send_action:
3: def send_action(method, *args)
=> 4: ret = super
5: default_render unless response_body
6: ret
7: end
[3] pry(#<PostsController>)>
How do I get a call stack of another thread?
There is Thread#backtrace method to get function backtrace for some thread:
https://ruby-doc.org/core-2.4.1/Thread.html#method-i-backtrace
backtrace
→ array click to toggle sourceReturns the current backtrace of the target thread.
For usage example check this project: https://github.com/frsyuki/sigdump (it will show backtraces and some memory usage info for ruby and jruby)
sigdump
- In short: SIGQUIT of Java VM for Ruby (Use signal to show stacktrace of a Ruby process without restarting it).... Just sending SIGCONT signal will dump backtrace and memory profile to /tmp/sigdump-.log file.
sigdump dumps following information (see also Sample output):
Backtrace of all threads
https://github.com/frsyuki/sigdump/blob/master/lib/sigdump.rb
dump_all_thread_backtrace(io)
...
Thread.list.each do |thread|
dump_backtrace(thread, io)
...
def self.dump_backtrace(thread, io)
status = thread.status
if status == nil
status = "finished"
elsif status == false
status = "error"
end
io.write " Thread #{thread} status=#{status} priority=#{thread.priority}\n"
if thread.backtrace
thread.backtrace.each {|bt|
io.write " #{bt}\n"
}
end
io.flush
nil
end
Related Topics
Is Time.Zone.Now.To_Date Equivalent to Date.Today
How to Handle Multiple Models in One Rails Form
How to Render a Plain HTML File with Sinatra
How to Use Rspec Expectations in Irb
Named Parameters in Ruby Structs
What Is a Robust Installation Process for Nokogiri (On Ubuntu)
Determine If One Array Contains All Elements of Another Array
What's the Difference Between Bundle.Setup and Bundle.Require
Differencebetween "Rails S" and "Bundle Exec Rails S"
Unable to Load Gem Cocoa Pods While Creating Repo
In Ruby, What Is Stored on the Stack
Adding Keywords to Ruby Syntax Highlighting for Notepad++
Capistrano 3 Execute Within a Directory
Bundler Puts My Gems in My Project Directory