Как получить объект трассировки стека в Ruby?

Мне нужно получить объект трассировки стека в Ruby; не печатать его, просто чтобы заставить его сделать запись и сброс для последующего анализа. Это возможно? Как?

Ответ 1

Вы можете использовать Kernel.caller для этого. Тот же метод используется при генерации трассировок стека для исключений.

Из документов:

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"]

Ответ 2

Попробуйте

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

Ответ 3

Попробуйте 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

дает:

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

Ответ 4

Для Ruby 2.0+ вы можете использовать Kernel#caller_locations. Это по существу то же самое, что Kernel#caller (см. ответ Sven Koschnicke), за исключением того, что вместо возврата массива строк он возвращает массив объектов Thread::Backtrace::Location. Thread::Backtrace::Location предоставляет такие методы, как path, lineno и base_label, что может быть полезно, когда вам нужен доступ к конкретным сведениям о трассировке стека, а не только необработанная строка.

От документы:

caller_locations (start = 1, length = nil) → array или nil

caller_locations (диапазон) → массив или nil

Возвращает текущий стек выполнения - массив, содержащий обратную трассировку объектов местоположения.

Подробнее см. Thread::Backtrace::Location.

Необязательный параметр запуска определяет количество начального стека записи, чтобы опустить из верхней части стека.

Второй необязательный параметр length может использоваться для ограничения количества записи возвращаются из стека.

Возвращает nil, если start больше, чем размер текущего исполнения стек.

Необязательно вы можете передать диапазон, который будет возвращать массив, содержащий записи в указанном диапазоне.

Пример использования:

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

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

Ответ 5

Вы также можете создать свой собственный, если хотите. Как показано в "Красноречивом рубине" Руса Олсена:

# 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)

Ответ 6

Thread.current.backtrace

Это даст вам массив, который содержит все строки, которые вы можете получить в любом обычном обратном направлении.