Ruby 如何跟踪堆栈跟踪高度以进行调试?

Ruby 如何跟踪堆栈跟踪高度以进行调试?,ruby,debugging,stack-trace,depth,Ruby,Debugging,Stack Trace,Depth,我希望我的代码执行以下操作: def debug (message) puts message.rjust(message.length + (stack_trace-1 * 2)) # -1 for the call to debug end def a debug "in a" b debug "end a" end def b debug "in b" c debug "end b" end def c debug "in c" meaningfu

我希望我的代码执行以下操作:

def debug (message)
  puts message.rjust(message.length + (stack_trace-1 * 2)) # -1 for the call to debug
end

def a
  debug "in a"
  b
  debug "end a"
end

def b
  debug "in b"
  c
  debug "end b"
end

def c
  debug "in c"
  meaningful_work
  debug "end c"
end
输出:

in a
  in b
    in c
    end c
  end b
end a
我以前在PHP中做过这样的工作,比如:

function echon($string){
  $nest_level = count(debug_backtrace()) - 1; // minus one to ignore the call to *this* function
  echo str_repeat("  ", $nest_level) . $string . "\n";
}
就我的google fu所知,没有一个Ruby等价于
debug\u backtrace
。我不想修改代码库中所有众多方法的调用来传递回溯,这是不必要的麻烦,而且很难恢复

这里是否有一些全局跟踪功能?

只需与
.length
一起使用即可<代码>调用方(0)。长度将为您提供当前堆栈深度

例如:

irb(main):001:0> caller(0)
=> ["(irb):1:in `irb_binding'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb/workspace.rb:86:in `eval'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb/workspace.rb:86:in `evaluate'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb/context.rb:380:in `evaluate'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb.rb:492:in `block (2 levels) in eval_input'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb.rb:624:in `signal_status'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb.rb:489:in `block in eval_input'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb/ruby-lex.rb:247:in `block (2 levels) in each_top_level_statement'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb/ruby-lex.rb:233:in `loop'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb/ruby-lex.rb:233:in `block in each_top_level_statement'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb/ruby-lex.rb:232:in `catch'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb/ruby-lex.rb:232:in `each_top_level_statement'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb.rb:488:in `eval_input'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb.rb:397:in `block in start'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb.rb:396:in `catch'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb.rb:396:in `start'", "/usr/bin/irb:12:in `<main>'"]
irb(main):002:0> caller(0).length
=> 17
irb(main):001:0>调用者(0)
=>[“(irb:1:in'irb_binding'”/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/Ruby/2.0.0/irb/workspace.rb:86:in'eval'”,/System/Library/Frameworks/Ruby.Frameworks/2.0/usr/lib/Ruby/2.0.0/irb/workspace.rb:86:in'evaluate',“/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/Ruby/2.0.0/irb/context.rb:380:in‘evaluate’”、/System/Library/Frameworks/Ruby.Frameworks/Ruby.Frameworks/Ruby.Frameworks/Ruby.Frameworks/Ruby.framework/2.0/usr/lib/Ruby/2.0.0/irb.rb:492:492:in‘信号_状态’”/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/Ruby/2.0.0/irb.rb:489:in`block in eval_input`,“/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/Ruby lex.rb:247:in`block(2 levels)in the event_top_level_语句”/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/Ruby/2.0.0/irb/Ruby-lex.rb:233:in‘loop’、/System/Library/Frameworks/Ruby.Frameworks/Ruby.framework/Ruby.framework/Versions/2.0/usr/Ruby/2.0.0/Ruby/2.0.0.rb:232:in‘catch’中“,”/System/Library/Frameworks/Ruby.framework/Versions/2.0/lib/Ruby/2.0.0/irb/Ruby lex.rb:232:在“每个顶级”语句中,“/System/Library/Frameworks/Ruby.framework/Frameworks/Ruby.framework/Versions/2.0/usr/lib/Ruby.0/irb.rb:488:在“eval\u输入”中,“/System/Library/Frameworks/Ruby.Frameworks/Versions/2.0/2.0/irb.rb/2.0:397:在“开始时的块中”,“/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/Ruby/2.0.0/irb.rb:396:in‘catch’”,/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/Ruby/2.0.0/irb.rb:396:in‘start’,/usr/bin/irb:12:in‘in’”]
irb(主):002:0>调用方(0).长度
=> 17

这里有一种方法可以实现@nneonneo的优秀建议

代码

INDENT = 2

def debug(msg=nil)
  @prev_arr_size ||= 1
  @arrived ||= false
  arr = caller(1)
  indent = ' '*(arr.size-2)*INDENT
  if msg
    puts indent + msg
    return
  end 
  meth, call_meth = method_str(arr[0]), method_str(arr[1])
  entering = (@prev_arr_size==arr.size) ? !@arrived : @prev_arr_size < arr.size
  msg1, msg2 = entering ? ["in ", "called from "] : ["end", "returning to"]
  puts indent  + "%s %s, %s %s" % [msg1, meth, msg2, call_meth]
  @prev_arr_size = arr.size
  @arrived = !@arrived
end

def method_str(str)
  file, _, meth = str.partition(/:.*?in\s+/)
  "#{meth[1..-2]} (#{file})"
end
def a
  debug
  # frivolous work
  b
  debug
end

def b
  debug
  c
  x = 5
  debug "It seems that x is now #{x}"
  # more frivolous work
  c
  debug
end

def c
  debug
  # meaningful_work
  debug
end

a
#=> in  a (t.rb), called from  <main> (t.rb)
#     in  b (t.rb), called from  a (t.rb)
#       in  c (t.rb), called from  b (t.rb)
#       end c (t.rb), returning to b (t.rb)
#     It seems that x is now 5
#       in  c (t.rb), called from  b (t.rb)
#       end c (t.rb), returning to b (t.rb)
#     end b (t.rb), returning to a (t.rb)
#   end a (t.rb), returning to <main> (t.rb)
INDENT=2
def调试(msg=nil)
@上一个arr大小| |=1
@到达| |=错误
arr=呼叫方(1)
缩进=''*(arr.size-2)*缩进
如果味精
放入缩进+味精
返回
结束
meth,call_meth=method_str(arr[0]),method_str(arr[1])
输入=(@prev\u arr\u size==arr.size)?!@到达:@prev\u arr\u size
示例

INDENT = 2

def debug(msg=nil)
  @prev_arr_size ||= 1
  @arrived ||= false
  arr = caller(1)
  indent = ' '*(arr.size-2)*INDENT
  if msg
    puts indent + msg
    return
  end 
  meth, call_meth = method_str(arr[0]), method_str(arr[1])
  entering = (@prev_arr_size==arr.size) ? !@arrived : @prev_arr_size < arr.size
  msg1, msg2 = entering ? ["in ", "called from "] : ["end", "returning to"]
  puts indent  + "%s %s, %s %s" % [msg1, meth, msg2, call_meth]
  @prev_arr_size = arr.size
  @arrived = !@arrived
end

def method_str(str)
  file, _, meth = str.partition(/:.*?in\s+/)
  "#{meth[1..-2]} (#{file})"
end
def a
  debug
  # frivolous work
  b
  debug
end

def b
  debug
  c
  x = 5
  debug "It seems that x is now #{x}"
  # more frivolous work
  c
  debug
end

def c
  debug
  # meaningful_work
  debug
end

a
#=> in  a (t.rb), called from  <main> (t.rb)
#     in  b (t.rb), called from  a (t.rb)
#       in  c (t.rb), called from  b (t.rb)
#       end c (t.rb), returning to b (t.rb)
#     It seems that x is now 5
#       in  c (t.rb), called from  b (t.rb)
#       end c (t.rb), returning to b (t.rb)
#     end b (t.rb), returning to a (t.rb)
#   end a (t.rb), returning to <main> (t.rb)
defa
调试
#无聊的工作
B
调试
结束
def b
调试
C
x=5
调试“似乎x现在是#{x}”
#更无聊的工作
C
调试
结束
def c
调试
#有意义的工作
调试
结束
A.
#=>在(t.rb)中,从(t.rb)调用
#在b(t.rb)中,从a(t.rb)调用
#在c(t.rb)中,从b(t.rb)调用
#c端(t.rb),返回b端(t.rb)
#看来x现在是5了
#在c(t.rb)中,从b(t.rb)调用
#c端(t.rb),返回b端(t.rb)
#b端(t.rb),返回a端(t.rb)
#结束a(t.rb),返回(t.rb)

这非常有效!我从长度中减去了大约45,因为深度非常大,这使我的代码非常可读。谢谢。虽然你的解决方案确实值得接受,但CarySwoveland的回答超出了范围,为未来的读者提供了丰富的资源,所以我改为接受他的。对不起!惊人的answer,如果我能接受两个,我会的。我可以提个建议吗?添加一个可选的调试参数,一个覆盖默认调试字符串的字符串,这样我们就可以传入诸如
“temp user\u id:{user\u id}”
之类的内容,并保持我们良好的格式。Deven,我做了您建议的更改,这是一个很好的更改。很抱歉,回复延迟了。