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

在所有调用处的事件钩子(callb_callc_call)。

:a_return

在所有返回处的事件钩子(returnb_returnc_return)。

:thread_begin

在线程开始时的事件钩子。

:thread_end

在线程结束时的事件钩子。

:fiber_switch

在纤程切换时的事件钩子。

:script_compiled

编译新的 Ruby 代码(使用 evalloadrequire)。

公共类方法

allow_reentry { block } 单击以切换源

通常,当 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
new(*events) { |tp| block } → tp 单击以切换源

返回一个新的 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
stat → obj 单击以切换源

返回 TracePoint 的内部信息。

返回值的原始内容是特定于实现的,并且将来可能会更改。

此方法仅用于调试 TracePoint 本身。

# File ruby_3_4_1/trace_point.rb, line 117
def self.stat
  Primitive.tracepoint_stat_s
end
trace(*events) { |tp| block } → obj 单击以切换源

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

公共实例方法

binding() 单击以切换源

返回从事件生成的绑定对象。

请注意,对于 :c_call:c_return 事件,该方法返回 nil,因为 C 方法本身没有绑定。

# File ruby_3_4_1/trace_point.rb, line 381
def binding
  Primitive.tracepoint_attr_binding
end
callee_id() 单击以切换源

返回被调用方法的名称。

# File ruby_3_4_1/trace_point.rb, line 337
def callee_id
  Primitive.tracepoint_attr_callee_id
end
defined_class() 单击以切换源

返回被调用方法的类或模块。

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
disable → true or false 单击以切换源
disable { block } → obj

停用跟踪。

如果已启用跟踪,则返回 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
enable(target: nil, target_line: nil, target_thread: nil) → true or false 单击以切换源
enable(target: nil, target_line: nil, target_thread: :default) { block } → obj

激活跟踪。

如果已启用跟踪,则返回 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

targettarget_linetarget_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
enabled? → true or false 单击以切换源

返回跟踪的当前状态。

# File ruby_3_4_1/trace_point.rb, line 304
def enabled?
  Primitive.tracepoint_enabled_p
end
eval_script() 单击以切换源

:script_compiled 事件中的 eval 方法返回已编译的源代码 (String)。如果从文件加载,则返回 nil

# File ruby_3_4_1/trace_point.rb, line 407
def eval_script
  Primitive.tracepoint_attr_eval_script
end
event() 单击以切换源

返回事件的类型。

有关更多信息,请参阅 TracePoint 中的事件

# File ruby_3_4_1/trace_point.rb, line 311
def event
  Primitive.tracepoint_attr_event
end
inspect → string 单击以切换源

返回一个字符串,其中包含人类可读的 TracePoint 状态。

# File ruby_3_4_1/trace_point.rb, line 104
def inspect
  Primitive.tracepoint_inspect
end
instruction_sequence() 单击以切换源

:script_compiled 事件中,返回由 RubyVM::InstructionSequence 实例表示的已编译指令序列。

请注意,此方法是 CRuby 特有的。

# File ruby_3_4_1/trace_point.rb, line 415
def instruction_sequence
  Primitive.tracepoint_attr_instruction_sequence
end
lineno() 单击以切换源

返回事件的行号。

# File ruby_3_4_1/trace_point.rb, line 316
def lineno
  Primitive.tracepoint_attr_lineno
end
method_id() 单击以切换源

返回被调用方法定义处的名称。

# File ruby_3_4_1/trace_point.rb, line 332
def method_id
  Primitive.tracepoint_attr_method_id
end
parameters() 单击以切换源

返回当前挂钩所属的方法或块的参数定义。格式与 Method#parameters 的格式相同。

# File ruby_3_4_1/trace_point.rb, line 327
def parameters
  Primitive.tracepoint_attr_parameters
end
path() 单击以切换源

返回正在执行的文件的路径。

# File ruby_3_4_1/trace_point.rb, line 321
def path
  Primitive.tracepoint_attr_path
end
raised_exception() 单击以切换源

返回在 :raise 事件中引发的或在 :rescue 事件中捕获的异常。

# File ruby_3_4_1/trace_point.rb, line 401
def raised_exception
  Primitive.tracepoint_attr_raised_exception
end
return_value() 单击以切换源

返回来自 :return:c_return:b_return 事件的返回值。

# File ruby_3_4_1/trace_point.rb, line 396
def return_value
  Primitive.tracepoint_attr_return_value
end
self() 单击以切换源

返回事件期间的跟踪对象。

类似于以下内容,但它返回 :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