TracePoint 類別

提供 Kernel#set_trace_func 功能的類別,使用友善的物件導向 API。

範例

我們可以使用 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 work 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 :line
# handler, all other handlers are ignored

# With reentry
# ------------

line_handler = TracePoint.new(:line) do |tp|
  next if tp.path != __FILE__ # only work in this file
  next if (__LINE__..__LINE__+3).cover?(tp.lineno) # don't be invoked from itself
  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 wil print "Class handler" twice: inside allow_reentry block in :line
# handler, other handlers are enabled.

請注意,範例顯示此方法的主要效果,但其實際用途是針對有時需要其他函式庫掛鉤不受偵錯器影響的偵錯函式庫。在此情況下應採取預防措施,以避免無限遞迴(請注意,我們需要從 :line 處理常式中濾出呼叫,否則它會無限呼叫自己)。

# File trace_point.rb, line 198
def self.allow_reentry
  Primitive.tracepoint_allow_reentry
end
new(*events) { |obj| block } → obj 按一下以切換來源

傳回新的 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 96
def self.new(*events)
  Primitive.tracepoint_new_s(events)
end
stat → obj 按一下以切換來源

傳回 TracePoint 的內部資訊。

傳回值的內容與實作有關。它可能會在未來變更。

此方法僅用於偵錯 TracePoint 本身。

# File trace_point.rb, line 118
def self.stat
  Primitive.tracepoint_stat_s
end
trace(*events) { |obj| block } → obj 按一下以切換來源

用於 TracePoint.new 的便利方法,會自動啟動追蹤。

trace = TracePoint.trace(:call) { |tp| [tp.lineno, tp.event] }
#=> #<TracePoint:enabled>

trace.enabled? #=> true
# File trace_point.rb, line 133
def self.trace(*events)
  Primitive.tracepoint_trace_s(events)
end

公開實例方法

binding() 按一下以切換來源

從事件傳回產生的繫結物件。

請注意,對於 :c_call:c_return 事件,方法會傳回 nil,因為 C 方法本身沒有繫結。

# File trace_point.rb, line 381
def binding
  Primitive.tracepoint_attr_binding
end
callee_id() 按一下以切換來源

傳回正在呼叫的方法的呼叫名稱

# File 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 trace_point.rb, line 373
def defined_class
  Primitive.tracepoint_attr_defined_class
end
disable → true 或 false 按一下以切換來源
disable { 區塊 } → 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 trace_point.rb, line 296
def disable
  Primitive.tracepoint_disable_m
end
enable(target: nil, target_line: nil, target_thread: nil) → true 或 false 按一下以切換來源
enable(target: nil, target_line: nil, target_thread: :default) { 區塊 } → 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 trace_point.rb, line 260
def enable(target: nil, target_line: nil, target_thread: :default)
  Primitive.tracepoint_enable_m(target, target_line, target_thread)
end
enabled? → true 或 false 按一下以切換來源

追蹤的目前狀態

# File trace_point.rb, line 304
def enabled?
  Primitive.tracepoint_enabled_p
end
eval_script() 按一下以切換來源

已編譯的原始碼 (String) 在 :script_compiled 事件的 *eval 方法上。如果從檔案載入,它會傳回 nil。

# File trace_point.rb, line 407
def eval_script
  Primitive.tracepoint_attr_eval_script
end
event() 按一下切換原始碼

事件類型

請參閱 TracePoint 的事件 以取得更多資訊。

# File trace_point.rb, line 311
def event
  Primitive.tracepoint_attr_event
end
inspect → string 按一下切換原始碼

傳回包含人類可讀 TracePoint 狀態的字串。

# File trace_point.rb, line 105
def inspect
  Primitive.tracepoint_inspect
end
instruction_sequence() 按一下切換原始碼

:script_compiled 事件上由 RubyVM::InstructionSequence 執行個體表示的已編譯指令序列。

請注意,此方法是 MRI 特有的。

# File trace_point.rb, line 415
def instruction_sequence
  Primitive.tracepoint_attr_instruction_sequence
end
lineno() 按一下切換原始碼

事件的行號

# File trace_point.rb, line 316
def lineno
  Primitive.tracepoint_attr_lineno
end
method_id() 按一下切換原始碼

傳回正在呼叫的方法定義的名稱

# File trace_point.rb, line 332
def method_id
  Primitive.tracepoint_attr_method_id
end
parameters() 按一下切換原始碼

傳回目前掛鉤所屬的方法或區塊的參數定義。格式與 Method#parameters 相同

# File trace_point.rb, line 327
def parameters
  Primitive.tracepoint_attr_parameters
end
path() 按一下切換原始碼

正在執行的檔案路徑

# File trace_point.rb, line 321
def path
  Primitive.tracepoint_attr_path
end
raised_exception() 按一下切換原始碼

:raise 事件引發的例外狀況值,或在 :rescue 事件中救援的例外狀況值。

# File trace_point.rb, line 401
def raised_exception
  Primitive.tracepoint_attr_raised_exception
end
return_value() 按一下切換原始碼

:return:c_return:b_return 事件的傳回值

# File trace_point.rb, line 396
def return_value
  Primitive.tracepoint_attr_return_value
end
self() 按一下切換原始碼

在事件期間傳回追蹤物件

與下列相同,但它會傳回 :c_call:c_return 事件的正確物件 (方法接收器)

trace.binding.eval('self')
# File trace_point.rb, line 391
def self
  Primitive.tracepoint_attr_self
end