Как получить ruby для печати полной backtrace вместо усеченной?
Когда я получаю исключения, он часто находится в глубине стека вызовов. Когда это происходит, чаще всего, скрытая строка кода скрыта от меня:
tmp.rb:7:in `t': undefined method `bar' for nil:NilClass (NoMethodError)
from tmp.rb:10:in `s'
from tmp.rb:13:in `r'
from tmp.rb:16:in `q'
from tmp.rb:19:in `p'
from tmp.rb:22:in `o'
from tmp.rb:25:in `n'
from tmp.rb:28:in `m'
from tmp.rb:31:in `l'
... 8 levels...
from tmp.rb:58:in `c'
from tmp.rb:61:in `b'
from tmp.rb:64:in `a'
from tmp.rb:67
То, что "... 8 уровней..." усечение вызывает у меня много проблем. У меня нет большого успеха в поисковой оптимизации для этого: Как мне сообщить ruby, что я хочу, чтобы дампы включали полный стек?
Ответы
Ответ 1
Исключительная ситуация # backtrace содержит весь стек:
def do_division_by_zero; 5 / 0; end
begin
do_division_by_zero
rescue => exception
puts exception.backtrace
raise # always reraise
end
(вдохновлено Питером Купером блогом Ruby Inside)
Ответ 2
Вы также можете сделать это, если хотите простой однострочный:
puts caller
Ответ 3
Это создает описание ошибки и красивую чистую отступы stacktrace:
begin
# Some exception throwing code
rescue => e
puts "Error during processing: #{$!}"
puts "Backtrace:\n\t#{e.backtrace.join("\n\t")}"
end
Ответ 4
У IRB есть настройка для этой ужасной "функции", которую вы можете настроить.
Создайте файл с именем ~/.irbrc
, который включает следующую строку:
IRB.conf[:BACK_TRACE_LIMIT] = 100
Это позволит вам увидеть 100 кадров стека в irb
, по крайней мере. Я не смог найти эквивалентную настройку для неинтерактивного времени выполнения.
Подробную информацию о настройке IRB можно найти в Pickaxe book.
Ответ 5
Один вкладыш для вызова:
begin; Whatever.you.want; rescue => e; puts e.message; puts; puts e.backtrace; end
Один вкладыш для callstack без всех драгоценных камней:
begin; Whatever.you.want; rescue => e; puts e.message; puts; puts e.backtrace.grep_v(/\/gems\//); end
Один лайнер для callstack без всех драгоценных камней и относительно текущего каталога
begin; Whatever.you.want; rescue => e; puts e.message; puts; puts e.backtrace.grep_v(/\/gems\//).map { |l| l.gsub(`pwd`.strip + '/', '') }; end
Ответ 6
Это подражает официальной трассе Ruby, если это важно для вас.
begin
0/0 # or some other nonsense
rescue => e
puts e.backtrace.join("\n\t")
.sub("\n\t", ": #{e}#{e.class ? " (#{e.class})" : ''}\n\t")
end
Поразительно, что он не обрабатывает "необработанное исключение" должным образом, сообщая ему как "RuntimeError", но местоположение правильное.
Ответ 7
Я получал эти ошибки при попытке загрузить тестовую среду (с помощью теста рейка или автотеста), и предложения IRB не помогли. Я закончил обертку всего моего теста /test _helper.rb в блоке начала и спасения, и это исправило ситуацию.
begin
class ActiveSupport::TestCase
#awesome stuff
end
rescue => e
puts e.backtrace
end
Ответ 8
[проверить все обратные потоки, чтобы найти виновника]
Даже полностью расширенный стек вызовов по-прежнему может скрыть фактическую строку с нарушением кода, когда вы используете более одного потока!
Пример: Один поток выполняет итерацию ruby Hash, другой поток пытается ее изменить. БУМ! Исключение! И проблема с трассировкой стека, которую вы получаете при попытке изменить "занятый" хеш, состоит в том, что он показывает вам цепочку функций вплоть до места, где вы пытаетесь изменить хэш, но НЕ показывает, кто в настоящее время выполняет итерацию параллельно ( кому это принадлежит)! Здесь вы узнаете, как распечатать трассировку стека для ВСЕХ текущих запущенных потоков. Вот как вы это делаете:
# This solution was found in comment by @thedarkone on https://github.com/rails/rails/issues/24627
rescue Object => boom
thread_count = 0
Thread.list.each do |t|
thread_count += 1
err_msg += "--- thread #{thread_count} of total #{Thread.list.size} #{t.object_id} backtrace begin \n"
# Lets see if we are able to pin down the culprit
# by collecting backtrace for all existing threads:
err_msg += t.backtrace.join("\n")
err_msg += "\n---thread #{thread_count} of total #{Thread.list.size} #{t.object_id} backtrace end \n"
end
# and just print it somewhere you like:
$stderr.puts(err_msg)
raise # always reraise
end
Вышеприведенный фрагмент кода полезен даже для образовательных целей, поскольку он может показать вам (например, рентгеновский), сколько потоков у вас на самом деле (по сравнению с тем, как вы считаете, что у вас есть), часто эти два являются разными числами;)
Ответ 9
Вы также можете использовать backtrace Ruby gem (я автор):
require 'backtrace'
begin
# do something dangerous
rescue StandardError => e
puts Backtrace.new(e)
end