class TracePoint
一个类,它以结构良好的面向对象 API 提供了 Kernel#set_trace_func 的功能。
示例
使用 TracePoint 来专门收集异常信息
trace = TracePoint.new(:raise) do |tp| p [tp.lineno, tp.event, tp.raised_exception] end #=> #<TracePoint:disabled> trace.enable #=> false 0 / 0 #=> [5, :raise, #<ZeroDivisionError: divided by 0>]
事件
如果您不指定要监听的事件类型,TracePoint 将包含所有可用事件。
注意: 请勿依赖当前事件集,因为此列表可能会发生更改。相反,建议指定您要使用的事件类型。
要过滤要跟踪的内容,您可以传递任意数量的以下内容作为 events
:line-
执行新行上的表达式或语句。
:class-
开始类或模块定义。
:end-
结束类或模块定义。
:call-
调用 Ruby 方法。
:return-
从 Ruby 方法返回。
:c_call-
调用 C 语言例程。
:c_return-
从 C 语言例程返回。
:raise-
引发异常。
:rescue-
捕获异常。
:b_call-
块入口处的事件挂钩。
:b_return-
块结束处的事件挂钩。
:a_call-
所有调用的事件挂钩(
call、b_call和c_call)。 :a_return-
所有返回的事件挂钩(
return、b_return和c_return)。 :thread_begin-
线程开始处的事件挂钩。
:thread_end-
线程结束处的事件挂钩。
:fiber_switch-
Fiber 切换处的事件挂钩。
:script_compiled-
新编译的 Ruby 代码(使用
eval、load或require)。
Public Class Methods
Source
# File trace_point.rb, line 200 def self.allow_reentry Primitive.attr! :use_block Primitive.tracepoint_allow_reentry end
通常,当 TracePoint 回调运行时,不会调用其他注册的回调,以避免因重入而产生的混淆。此方法允许在给定块内重入。请谨慎使用此方法,以避免无限回调调用。
如果已经在允许重入时调用,它将引发 RuntimeError。
示例
# Without reentry # --------------- line_handler = TracePoint.new(:line) do |tp| next if tp.path != __FILE__ # Only works in this file puts "Line handler" binding.eval("class C; end") end.enable class_handler = TracePoint.new(:class) do |tp| puts "Class handler" end.enable class B end # This script will print "Class handler" only once: when inside the :line # handler, all other handlers are ignored. # With reentry # ------------ line_handler = TracePoint.new(:line) do |tp| next if tp.path != __FILE__ # Only works in this file next if (__LINE__..__LINE__+3).cover?(tp.lineno) # Prevent infinite calls puts "Line handler" TracePoint.allow_reentry { binding.eval("class C; end") } end.enable class_handler = TracePoint.new(:class) do |tp| puts "Class handler" end.enable class B end # This will print "Class handler" twice: inside the allow_reentry block in the :line # handler, other handlers are enabled.
请注意,此示例显示了该方法的主要作用,但其实际用途是调试库,这些库有时需要其他库的挂钩不被调试器内部的跟踪点处理所影响。在这种情况下,应采取预防措施防止无限递归(请注意,我们需要从 :line 处理程序中过滤掉它自己的调用,否则它将无限调用自身)。
Source
# File trace_point.rb, line 96 def self.new(*events) Primitive.attr! :use_block Primitive.tracepoint_new_s(events) end
返回一个新的 TracePoint 对象,默认情况下不启用。
要激活 TracePoint 对象,请使用 TracePoint#enable
trace = TracePoint.new(:call) do |tp| p [tp.lineno, tp.defined_class, tp.method_id, tp.event] end #=> #<TracePoint:disabled> trace.enable #=> false puts "Hello, TracePoint!" # ... # [48, IRB::Notifier::AbstractNotifier, :printf, :call] # ...
要禁用跟踪,请使用 TracePoint#disable。
trace.disable
有关可能的事件和更多信息,请参阅 TracePoint 的 事件。
必须提供一个块;否则,将引发 ArgumentError。
如果所提供的事件过滤器不支持跟踪方法,则会引发 RuntimeError。
TracePoint.trace(:line) do |tp| p tp.raised_exception end #=> RuntimeError: 'raised_exception' not supported by this event
如果在块外部调用跟踪方法,则会引发 RuntimeError。
TracePoint.trace(:line) do |tp| $tp = tp end $tp.lineno #=> access from outside (RuntimeError)
禁止从其他 ractor、线程或 fiber 访问。TracePoint 按 ractor 激活,因此如果您在一个 ractor 中启用了 TracePoint,其他 ractor 将不受影响。
Source
# File trace_point.rb, line 119 def self.stat Primitive.tracepoint_stat_s end
返回 TracePoint 的内部信息。
返回值的内容是实现特定的,并且将来可能会更改。
此方法仅用于调试 TracePoint 本身。
Source
# File trace_point.rb, line 134 def self.trace(*events) Primitive.attr! :use_block Primitive.tracepoint_trace_s(events) end
TracePoint.new 的便捷方法,可自动激活跟踪。
trace = TracePoint.trace(:call) { |tp| [tp.lineno, tp.event] } #=> #<TracePoint:enabled> trace.enabled? #=> true
Public Instance Methods
Source
# File trace_point.rb, line 383 def binding Primitive.tracepoint_attr_binding end
从事件返回生成的绑定对象。
请注意,对于 :c_call 和 :c_return 事件,该方法返回 nil,因为 C 方法本身没有绑定。
Source
# File trace_point.rb, line 339 def callee_id Primitive.tracepoint_attr_callee_id end
返回被调用方法的被调用名称。
Source
# File trace_point.rb, line 375 def defined_class Primitive.tracepoint_attr_defined_class end
返回被调用方法的类或模块。
class C; def foo; end; end trace = TracePoint.new(:call) do |tp| p tp.defined_class #=> C end.enable do C.new.foo end
如果方法由模块定义,则返回该模块。
module M; def foo; end; end class C; include M; end trace = TracePoint.new(:call) do |tp| p tp.defined_class #=> M end.enable do C.new.foo end
注意: defined_class 返回单例类。
Kernel#set_trace_func 的第六个块参数传递了由单例类附加的原始类。
这是 Kernel#set_trace_func 和 TracePoint 之间的区别。
class C; def self.foo; end; end trace = TracePoint.new(:call) do |tp| p tp.defined_class #=> #<Class:C> end.enable do C.foo end
Source
# File trace_point.rb, line 297 def disable Primitive.attr! :use_block Primitive.tracepoint_disable_m end
禁用跟踪。
如果跟踪已启用,则返回 true。如果跟踪已禁用,则返回 false。
trace.enabled? #=> true trace.disable #=> true (previous status) trace.enabled? #=> false trace.disable #=> false
如果提供了块,则跟踪仅在块的范围内禁用。
trace.enabled? #=> true trace.disable do trace.enabled? # Only disabled for this block end trace.enabled? #=> true
注意:您无法在块内访问事件挂钩。
trace.disable { p tp.lineno } #=> RuntimeError: access from outside
Source
# File trace_point.rb, line 261 def enable(target: nil, target_line: nil, target_thread: :default) Primitive.attr! :use_block Primitive.tracepoint_enable_m(target, target_line, target_thread) end
激活跟踪。
如果跟踪已启用,则返回 true。如果跟踪已禁用,则返回 false。
trace.enabled? #=> false trace.enable #=> false (previous state) # trace is enabled trace.enabled? #=> true trace.enable #=> true (previous state) # trace is still enabled
如果提供了块,则跟踪仅在块执行期间启用。如果 target 和 target_line 都为 nil,则当提供块时,target_thread 将默认为当前线程。
trace.enabled? #=> false trace.enable do trace.enabled? # Only enabled for this block and thread end trace.enabled? #=> false
target、target_line 和 target_thread 参数用于将跟踪限制到指定的代码对象。target 应该是 RubyVM::InstructionSequence.of 将返回指令序列的代码对象。
t = TracePoint.new(:line) { |tp| p tp } def m1 p 1 end def m2 p 2 end t.enable(target: method(:m1)) m1 # Prints #<TracePoint:line test.rb:4 in `m1'> m2 # Prints nothing
注意:您无法在 enable 块内访问事件挂钩。
trace.enable { p tp.lineno } #=> RuntimeError: access from outside
Source
# File trace_point.rb, line 306 def enabled? Primitive.tracepoint_enabled_p end
返回跟踪的当前状态。
Source
# File trace_point.rb, line 409 def eval_script Primitive.tracepoint_attr_eval_script end
在 :script_compiled 事件上,从 eval 方法返回编译后的源代码(String)。如果从文件加载,则返回 nil。
Source
# File trace_point.rb, line 313 def event Primitive.tracepoint_attr_event end
返回事件的类型。
有关更多信息,请参阅 TracePoint 的 事件。
Source
# File trace_point.rb, line 106 def inspect Primitive.tracepoint_inspect end
返回一个包含人类可读的 TracePoint 状态的字符串。
Source
# File trace_point.rb, line 417 def instruction_sequence Primitive.tracepoint_attr_instruction_sequence end
在 :script_compiled 事件上,以 RubyVM::InstructionSequence 实例的形式返回编译的指令序列。
请注意,此方法是 CRuby 特定的。
Source
# File trace_point.rb, line 318 def lineno Primitive.tracepoint_attr_lineno end
返回事件的行号。
Source
# File trace_point.rb, line 334 def method_id Primitive.tracepoint_attr_method_id end
返回被调用方法的定义名称。
Source
# File trace_point.rb, line 329 def parameters Primitive.tracepoint_attr_parameters end
返回当前挂钩所属的方法或块的参数定义。格式与 Method#parameters 相同。
Source
# File trace_point.rb, line 323 def path Primitive.tracepoint_attr_path end
返回正在执行的文件的路径。
Source
# File trace_point.rb, line 403 def raised_exception Primitive.tracepoint_attr_raised_exception end
返回在 :raise 事件上引发的异常或在 :rescue 事件上捕获的异常。
Source
# File trace_point.rb, line 398 def return_value Primitive.tracepoint_attr_return_value end
返回 :return、:c_return 和 :b_return 事件的返回值。
Source
# File trace_point.rb, line 393 def self Primitive.tracepoint_attr_self end
在事件期间返回跟踪对象。
与以下内容类似,但它为 :c_call 和 :c_return 事件返回正确的对象(方法接收者)
trace.binding.eval('self')