Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/ant/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何记录每个';在Ruby程序中调用了什么?_Ruby_Logging_Methods - Fatal编程技术网

如何记录每个';在Ruby程序中调用了什么?

如何记录每个';在Ruby程序中调用了什么?,ruby,logging,methods,Ruby,Logging,Methods,我继承了一大堆Ruby代码,坦率地说,对于像我这样的凡人来说,这几乎是不可能理解的。它实际上是Rspec单元测试代码,但它的结构“非常不寻常” 我希望能够运行代码,并将以下信息记录在某个地方: 每个被调用的方法,包括定义该方法的类的名称,以及定义被调用方法的文件名(是的,我们在多个不同的文件中定义了相同的类/方法,很难知道调用的是哪一个) (可选)传递给调用的每个方法的参数 这样,我就可以开始尝试重构它了。没有它,由于代码库(20k+单元测试用例)的大小,将是一项非常困难的任务 我负担不起对

我继承了一大堆Ruby代码,坦率地说,对于像我这样的凡人来说,这几乎是不可能理解的。它实际上是Rspec单元测试代码,但它的结构“非常不寻常”

我希望能够运行代码,并将以下信息记录在某个地方:

  • 每个被调用的方法,包括定义该方法的类的名称,以及定义被调用方法的文件名(是的,我们在多个不同的文件中定义了相同的类/方法,很难知道调用的是哪一个)
  • (可选)传递给调用的每个方法的参数
这样,我就可以开始尝试重构它了。没有它,由于代码库(20k+单元测试用例)的大小,将是一项非常困难的任务

我负担不起对正在运行的代码进行大规模编辑,因为即使您使用了苛刻的语言(例如,频繁使用),代码也会中断。相反,我需要能够在现有状态下插入代码,或者对现有代码进行最小的更改

有没有一种方法可以记录这一级别的详细信息,而不必对代码库进行大量更改?我已经看过Ruby profiler,看看它是否有帮助,而且它可能有帮助;我很好奇是否有更好的方法(特别是记录包含调用方法的文件名)


提前感谢

这绝对是可能的——事实上,甚至有一种方法可以做到这一点!只需在您希望开始记录内容之前的代码中添加以下内容:

set_trace_func proc { |event, file, line, id, binding, classname|
  printf "%8s %s:%-2d %10s %8s\n", event, file, line, id, classname
}
您想要的秘方来自,如上所述:

  • 设置跟踪函数(proc)=>proc
  • set_trace_func(nil)=>nil
proc
建立为跟踪处理程序,如果参数为
nil
,则禁用跟踪
proc
最多使用六个参数:事件名称、文件名、行号、对象id、绑定和类名称<代码>过程在事件发生时调用。事件包括:
c-call
(调用c-language例程)、
c-return
(从c-language例程返回)、
call
(调用Ruby方法)、
class
(启动类或模块定义)、
end
(完成类或模块定义)、
(在新行上执行代码)、
raise
(引发异常)和
return
(从Ruby方法返回)。在进程上下文中禁用跟踪

下面是一个方便的示例:

class Test
  def test
    a = 1
    b = 2
  end
end

set_trace_func proc { |event, file, line, id, binding, classname|
  printf "%8s %s:%-2d %10s %8s\n", event, file, line, id, classname
}

t = Test.new
t.test
(注意:除非您想要一个巨大的文本滚动屏幕,否则不要在
irb
中尝试此操作。)结果输出为:

    line test.rb:11               false
  c-call test.rb:11        new    Class
  c-call test.rb:11 initialize   Object
c-return test.rb:11 initialize   Object
c-return test.rb:11        new    Class
    line test.rb:12               false
    call test.rb:2        test     Test
    line test.rb:3        test     Test
    line test.rb:4        test     Test
  return test.rb:4        test     Test

您可以使用上面的格式字符串来获得想要记录的结果(例如,听起来您只对
call
事件感兴趣)。希望这会有所帮助,祝您好运,顺利完成所有这些单元测试!

我想包括事件发生时的秒数以及每个函数花费的时间

start = DateTime.now.strftime('%Q').to_i / 1000.0
set_trace_func proc { |event, file, line, id, binding, classname|
  now_ms = DateTime.now.strftime('%Q').to_i / 1000.0
  duration = '%.3f' % (now_ms - start)
  start = DateTime.now.strftime('%Q').to_i / 1000.0
  printf "%s %s %8s %s:%-2d %10s %8s\n", DateTime.now.strftime("%S.%L"), duration, event, file, line, id, classname
}

AdminUser.create(password: "password", password_confirmation: "password", email: email)

set_trace_func nil
我试图调试为什么创建用户和登录ActiveAdmin花费了这么长时间

05.761 0.000 c-return /Users/nperry/.rvm/gems/ruby-2.1.2@rxair/gems/bcrypt-3.1.7/lib/bcrypt/engine.rb:51       to_s   String
05.761 0.000   c-call /Users/nperry/.rvm/gems/ruby-2.1.2@rxair/gems/bcrypt-3.1.7/lib/bcrypt/engine.rb:51 __bc_crypt BCrypt::Engine
09.736 63.975 c-return /Users/nperry/.rvm/gems/ruby-2.1.2@rxair/gems/bcrypt-3.1.7/lib/bcrypt/engine.rb:51 __bc_crypt BCrypt::Engine
09.736 0.000   return /Users/nperry/.rvm/gems/ruby-2.1.2@rxair/gems/bcrypt-3.1.7/lib/bcrypt/engine.rb:59 hash_secret BCrypt::Engine
09.736 0.000   c-call /Users/nperry/.rvm/gems/ruby-2.1.2@rxair/gems/bcrypt-3.1.7/lib/bcrypt/password.rb:46        new    Class

从这一点我知道Ruby在
\uu bc\u crypt

上花了一分钟多的时间,最近,
set\u trace\u func
被弃用了:

注意:此方法已过时,请改用跟踪点

我们可以使用TracePoint,它支持
set\u trace\u func

trace = TracePoint.new(:call) do |tp|
  puts "#{tp.defined_class}##{tp.method_id} got called (#{tp.path}:#{tp.lineno})"
end

trace.enable
# do stuff here
trace.disable
这实际上比
set_trace_func
更强大,因为您可以在方便的时候启用和禁用。您可以有选择地连接到以下事件:
:line、:class、:end、:call、:return、:c_call、:c_return、:raise、:b_call、:b_return、:thread_begin、:thread_end

这里有一个完整的例子:

class MyClass
  def initialize
  end
  def y
    z
  end
  def z
   1 + 1
  end
end

trace = TracePoint.new(:call) do |tp|
  puts "#{tp.defined_class}##{tp.method_id} got called (#{tp.path}:#{tp.lineno})"
end

trace.enable # note
MyClass.new.y
trace.disable
  # MyClass#initialize got called (./trace.rb:4)
  # MyClass#y got called (./trace.rb:7)
  # MyClass#z got called (./trace.rb:10)

您是否考虑过静态分析器,或者您只是在寻找实际运行代码的东西?Doxygen输出了一些很好的调用方/被调用方图,还没有查看它是否支持Ruby,但调用图对于理解现有代码非常有用。我相当肯定Doxygen不支持Ruby-如果支持,它肯定会被用于ul给我,但我找不到任何关于Doxygen支持Ruby的信息。我更喜欢实际运行代码的东西,主要是因为require的处理顺序会影响多个中的哪一个(不相同)将使用给定方法的定义。正如我所说,这是一个丑陋的代码库…哇-这正是我所希望的。谢谢John!没问题。Ruby使用这种瑞士军刀的东西非常方便。听起来你的Bcrypt
成本相当高。T.J.Shuck(前15分钟左右).我相信我们当时确实解决了这个问题,而且这个问题肯定是B CRYPT。