Как получить 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