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