How to get a stack trace object in Ruby?

RubyStackStack Trace

Ruby Problem Overview


I need to get a stack trace object in Ruby; not to print it, just to get it to do some recording and dumping for later analysis. Is that possible? How?

Ruby Solutions


Solution 1 - Ruby

You can use Kernel.caller for this. The same method is used when generating stack traces for exceptions.

From the docs:

def a(skip)
  caller(skip)
end
def b(skip)
  a(skip)
end
def c(skip)
  b(skip)
end
c(0) #=> ["prog:2:in `a'", "prog:5:in `b'", "prog:8:in `c'", "prog:10"]
c(1) #=> ["prog:5:in `b'", "prog:8:in `c'", "prog:11"]
c(2) #=> ["prog:8:in `c'", "prog:12"]
c(3) #=> ["prog:13"]

Solution 2 - Ruby

Try

Thread.current.backtrace.join("\n")

Solution 3 - Ruby

Try error.backtrace:

# Returns any backtrace associated with the exception.  
# The backtrace is an array of strings, each containing either ``filename:lineNo: in `method’’’ or ``filename:lineNo.’‘

def a
  raise "boom"
end

def b
  a()
end

begin
  b()
rescue => detail
  print detail.backtrace.join("\n")
end

produces:

prog.rb:2:in `a'
prog.rb:6:in `b'
prog.rb:10

Solution 4 - Ruby

For Ruby 2.0+, you can use Kernel#caller_locations. It is essentially the same as Kernel#caller (covered in Sven Koschnicke's answer), except that instead of returning an array of strings, it returns an array of Thread::Backtrace::Location objects. Thread::Backtrace::Location provides methods such as path, lineno, and base_label, which may be useful when you need access to specific details about the stack trace, and not just a raw string.

From the docs:

> ## caller_locations(start=1, length=nil) → array or nil > ## caller_locations(range) → array or nil > > Returns the current execution stack—an array containing backtrace > location objects. > > See Thread::Backtrace::Location for more information. > > The optional start parameter determines the number of initial stack > entries to omit from the top of the stack. > > A second optional length parameter can be used to limit how many > entries are returned from the stack. > > Returns nil if start is greater than the size of current execution > stack. > > Optionally you can pass a range, which will return an array containing > the entries within the specified range.

Usage example:

def a
  caller_locations(0)
end
def b
  a
end
def c
  b
end

c.map(&:base_label)
#=> ["a", "b", "c", "<main>"]

Solution 5 - Ruby

Thread.current.backtrace

This will give you an array which contains all the lines that you may get in any normal backtrace.

Solution 6 - Ruby

You can create your own if you want as well. As demonstrated in Eloquent Ruby by Russ Olsen:

# define a proc to use that will handle your trace 
proc_object = proc do |event, file, line, id, binding, klass| 
  puts "#{event} in #{file}/#{line} #{id} #{klass}"
end 

# tell Ruby to use your proc on traceable events
set_trace_func(proc_object)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionpupenoView Question on Stackoverflow
Solution 1 - RubySven KoschnickeView Answer on Stackoverflow
Solution 2 - RubyAlex BondarView Answer on Stackoverflow
Solution 3 - RubyNikita RybakView Answer on Stackoverflow
Solution 4 - RubyAjedi32View Answer on Stackoverflow
Solution 5 - RubyRajat BansalView Answer on Stackoverflow
Solution 6 - RubySammy LarbiView Answer on Stackoverflow