Как заставить рубин распечатать полную трассировку вместо усеченной? - PullRequest
143 голосов
/ 18 декабря 2008

Когда я получаю исключения, это часто происходит из глубины стека вызовов. Когда это происходит, чаще всего настоящая оскорбительная строка кода скрывается от меня:

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 уровней ..." доставляет мне много хлопот. У меня нет особого успеха в поиске в Google: как мне сказать ruby, что я хочу, чтобы дампы включали полный стек?

Ответы [ 9 ]

207 голосов
/ 18 декабря 2008

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

158 голосов
/ 11 октября 2011

Вы также можете сделать это, если хотите простую однострочную строку:

puts caller
93 голосов
/ 16 февраля 2011

Это дает описание ошибки и красивую чистую трассировку с отступом:

begin               
 # Some exception throwing code
rescue => e
  puts "Error during processing: #{$!}"
  puts "Backtrace:\n\t#{e.backtrace.join("\n\t")}"
end
45 голосов
/ 27 июня 2009

IRB имеет настройку для этой ужасной «функции», которую вы можете настроить.

Создайте файл с именем ~/.irbrc, содержащий следующую строку:

IRB.conf[:BACK_TRACE_LIMIT] = 100

Это позволит вам увидеть 100 кадров стека в irb, по крайней мере. Мне не удалось найти эквивалентную настройку для неинтерактивной среды выполнения.

Подробную информацию о настройке IRB можно найти в Книге кирки .

9 голосов
/ 07 февраля 2017

Один вкладыш для стека вызовов:

begin; Whatever.you.want; rescue => e; puts e.message; puts; puts e.backtrace; end

Один вкладыш для стека вызовов без всех драгоценных камней:

begin; Whatever.you.want; rescue => e; puts e.message; puts; puts e.backtrace.grep_v(/\/gems\//); end

Один вкладыш для стека вызовов без всех гемов и относительно текущего каталога

begin; Whatever.you.want; rescue => e; puts e.message; puts; puts e.backtrace.grep_v(/\/gems\//).map { |l| l.gsub(`pwd`.strip + '/', '') }; end
7 голосов
/ 24 февраля 2016

Это имитирует официальную трассировку 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», но местоположение указано правильно.

3 голосов
/ 01 апреля 2010

Я получал эти ошибки при попытке загрузить свою тестовую среду (с помощью rake test или autotest), и предложения IRB не помогли. В итоге я завернул весь свой test / test_helper.rb в блок begin / rescue, и это все исправило.

begin
  class ActiveSupport::TestCase
    #awesome stuff
  end
rescue => e
  puts e.backtrace
end
0 голосов
/ 12 октября 2018

Вы также можете использовать backtrace Ruby gem (я автор):

require 'backtrace'
begin
  # do something dangerous
rescue StandardError => e
  puts Backtrace.new(e)
end
0 голосов
/ 23 января 2017

[проверить все нити следов, чтобы найти виновника]
Даже полностью расширенный стек вызовов все еще может скрывать от вас актуальную строку кода, когда вы используете более одного потока!

Пример: один поток выполняет итерации 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

Приведенный выше фрагмент кода полезен даже для образовательных целей, поскольку он может показать вам (например, рентген), сколько потоков у вас на самом деле (по сравнению с тем, сколько вы думаете, у вас есть - довольно часто эти два числа разные;) 1009 *

...