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
-
在纤程切换时的事件钩子。
:script_compiled
-
编译新的 Ruby 代码(使用
eval
,load
或require
)。
公共类方法
通常,当 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 处理程序中过滤掉自身的调用,否则它会无限次调用自身)。
# File ruby_3_4_1/trace_point.rb, line 198 def self.allow_reentry Primitive.attr! :use_block Primitive.tracepoint_allow_reentry 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)
也禁止从其他线程访问。
# File ruby_3_4_1/trace_point.rb, line 94 def self.new(*events) Primitive.attr! :use_block Primitive.tracepoint_new_s(events) end
返回 TracePoint
的内部信息。
返回值的原始内容是特定于实现的,并且将来可能会更改。
此方法仅用于调试 TracePoint
本身。
# File ruby_3_4_1/trace_point.rb, line 117 def self.stat Primitive.tracepoint_stat_s end
是 TracePoint.new
的便利方法,可自动激活跟踪。
trace = TracePoint.trace(:call) { |tp| [tp.lineno, tp.event] } #=> #<TracePoint:enabled> trace.enabled? #=> true
# File ruby_3_4_1/trace_point.rb, line 132 def self.trace(*events) Primitive.attr! :use_block Primitive.tracepoint_trace_s(events) end
公共实例方法
返回从事件生成的绑定对象。
请注意,对于 :c_call
和 :c_return
事件,该方法返回 nil
,因为 C 方法本身没有绑定。
# File ruby_3_4_1/trace_point.rb, line 381 def binding Primitive.tracepoint_attr_binding end
返回被调用方法的名称。
# File ruby_3_4_1/trace_point.rb, line 337 def callee_id Primitive.tracepoint_attr_callee_id 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
的第 6 个块参数传递由单例类附加的原始类。
这是 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
# File ruby_3_4_1/trace_point.rb, line 373 def defined_class Primitive.tracepoint_attr_defined_class 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
# File ruby_3_4_1/trace_point.rb, line 295 def disable Primitive.attr! :use_block Primitive.tracepoint_disable_m 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
# File ruby_3_4_1/trace_point.rb, line 259 def enable(target: nil, target_line: nil, target_thread: :default) Primitive.attr! :use_block Primitive.tracepoint_enable_m(target, target_line, target_thread) end
返回跟踪的当前状态。
# File ruby_3_4_1/trace_point.rb, line 304 def enabled? Primitive.tracepoint_enabled_p end
从 :script_compiled
事件中的 eval 方法返回已编译的源代码 (String
)。如果从文件加载,则返回 nil
。
# File ruby_3_4_1/trace_point.rb, line 407 def eval_script Primitive.tracepoint_attr_eval_script end
返回事件的类型。
有关更多信息,请参阅 TracePoint
中的事件。
# File ruby_3_4_1/trace_point.rb, line 311 def event Primitive.tracepoint_attr_event end
返回一个字符串,其中包含人类可读的 TracePoint
状态。
# File ruby_3_4_1/trace_point.rb, line 104 def inspect Primitive.tracepoint_inspect end
在 :script_compiled
事件中,返回由 RubyVM::InstructionSequence
实例表示的已编译指令序列。
请注意,此方法是 CRuby 特有的。
# File ruby_3_4_1/trace_point.rb, line 415 def instruction_sequence Primitive.tracepoint_attr_instruction_sequence end
返回事件的行号。
# File ruby_3_4_1/trace_point.rb, line 316 def lineno Primitive.tracepoint_attr_lineno end
返回被调用方法定义处的名称。
# File ruby_3_4_1/trace_point.rb, line 332 def method_id Primitive.tracepoint_attr_method_id end
返回当前挂钩所属的方法或块的参数定义。格式与 Method#parameters
的格式相同。
# File ruby_3_4_1/trace_point.rb, line 327 def parameters Primitive.tracepoint_attr_parameters end
返回正在执行的文件的路径。
# File ruby_3_4_1/trace_point.rb, line 321 def path Primitive.tracepoint_attr_path end
返回在 :raise
事件中引发的或在 :rescue
事件中捕获的异常。
# File ruby_3_4_1/trace_point.rb, line 401 def raised_exception Primitive.tracepoint_attr_raised_exception end
返回来自 :return
,:c_return
和 :b_return
事件的返回值。
# File ruby_3_4_1/trace_point.rb, line 396 def return_value Primitive.tracepoint_attr_return_value end
返回事件期间的跟踪对象。
类似于以下内容,但它返回 :c_call
和 :c_return
事件的正确对象(方法接收器)
trace.binding.eval('self')
# File ruby_3_4_1/trace_point.rb, line 391 def self Primitive.tracepoint_attr_self end