Как настроить ruby ​​для ввода отладчика в Ctrl-C (SIGINT)?

Я хотел бы ввести отладчик после ввода ctrl-C (или отправки SIGINT). У меня установлен отладчик (я запускаю Ruby 1.9.3) и проверял, что он работает. Я добавил это в свои установочные файлы (это для Padrino, но я предполагаю, что это будет похоже на Rails):

# file: config/boot.rb
Padrino.before_load do
  trap("SIGINT") { debugger } if Padrino.env == :development
end

... но ввод Ctrl-C не вызывает отладчик. На самом деле, если я заменю debugger на puts "saw an interrupt!", набрав Ctrl-C, это не приведет к тому, что печать тоже произойдет.

Обновление

Следуя это предложение от Майка Данлави, я пробовал явно называть catch Interrupt из отладчика:

$ rdebug `which padrino` console
^Z^Z$HOME/usr/bin/padrino:9
require 'rubygems'
(rdb:1) catch Interrupt
Catch exception Interrupt.
(rdb:1) c
=> Loading development console (Padrino v.0.10.7)
=> Loading Application BlueDotAe
=> Loading Application Admin
irb(main):001:0>   C-c C-c^C
irb(main):001:0> 

Без радости - прерывание не попало в отладчик.

Что мне не хватает?

Ответ 1

Если вы хотите захватить SIGINT во время работы в консоли, короткий ответ таков: вы не можете, если не используете IRB с обезьяной. Каждое приложение Ruby (будь то padrino, rails или whatnot), использующее консоль, в конечном итоге вызывает usr/lib/ruby/1.9.1/irb.rb, а в IRB.start:

trap("SIGINT") do
  irb.signal_handle
end

... непосредственно перед входом в основной цикл. Это заменит любую ловушку ( "SIGINT" ), которую вы могли бы ввести в свой код запуска.

Но если вы хотите захватить SIGINT в файле script (например, если вы хотите профилировать свой код, как описано Майком Данлави здесь), вы может создать файл script, например:

# File: profile_complex_operation.rb
trap("SIGINT") { debugger }
MyApp.complex_operation

а затем вызовите его, как в:

$ ruby profile_complex_operation.rb

Теперь, когда вы нажмете ^ C (или отправьте SIGINT из другого процесса), он войдет в отладчик.

Ответ 2

Вы можете попытаться использовать обертка GDB для Ruby (GitHub).

Установите на Linux через:

sudo apt-get install gdb python-dev ncurses-dev ruby-rvm
gem install gdb.rb

Основное использование:

require 'gdb'

# create a new GDB::Ruby instance and attach it to
# pid 12345
gdb = GDB::Ruby.new(12345)

# print the (ruby) backtrace of the remote process
gdb.backtrace.each { |line| puts line }

# show the current local variables, and their values
p gdb.local_variables

# evaluate arbitrary ruby code in the remote process
p gdb.eval('%(pid #{$$})')

# show how many instances of each class exist in the
# remote process
p gdb.object_space

# raise an exception in the remote process
gdb.raise Exception, "go boom!"

# close the connection to the remote process
gdb.quit

Или, чтобы отладить зависающий процесс, присоедините его через:

rvmsudo gdb.rb PID

то

# in gdb get a ruby stacktrace with file names and line numbers
# here I'm filtering by files that are actually in my app dir
(gdb) ruby eval caller.select{|l| l =~ /app\//}

Источник: Использование gdb для проверки зависающего рубинового процесса

Некоторые альтернативы:

  • rbtrace - как strace, но для ruby-кода (использование: rbtrace -p <PID> --firehose).
  • debug.rb script от tmm1 (автор gdb.rb), который может помочь отладить процесс с помощью strace/gdb.

См. также: