Как настроить 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.
См. также: