如何配置Ruby在按下Ctrl-C(SIGINT)时进入调试器?

3

我希望在按下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也不会发生打印。

更新

根据Mike Dunlavey建议,我尝试在调试器中显式调用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> 

没有进入调试器 -- 中断未产生任何结果。

我错过了什么?

2个回答

4

如果你想在控制台运行时捕获SIGINT,简短的答复是:除非你monkey-patch了IRB,否则无法实现。每个使用控制台的Ruby应用程序(无论是padrino、rails还是其他)都将最终调用usr/lib/ruby/1.9.1/irb.rb,而在IRB.start中它会执行以下操作:

trap("SIGINT") do
  irb.signal_handle
end

在进入主循环之前,添加一行代码以覆盖您可能已经在启动代码中设置的任何“SIGINT”陷阱。

但是,如果您想在脚本文件中捕获SIGINT(例如,如果您想按照Mike Dunlavey在这里描述的方式对代码进行分析),您可以创建一个脚本文件,如下所示:

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

然后按以下方式调用:

$ ruby profile_complex_operation.rb

现在,当你按下^C(或从另外一个进程发送SIGINT信号)时,它将进入调试器。

只是澄清一下 - 使用此方法,当您进入调试器时,您是在陷阱点还是在发送 SIGINT 时的代码执行点进入调用堆栈? - Matt Sanders

1
您可以尝试使用Ruby的GDB包装器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检查挂起的ruby进程

一些替代方案:

  • rbtrace - 类似于strace,但适用于ruby代码(用法:rbtrace -p <PID> --firehose)。
  • tmm1编写的{{debug.rb脚本,可帮助使用strace/gdb调试进程。

另请参阅:


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接