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
-
所有呼叫(
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 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
傳回新的 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
傳回 TracePoint
的內部資訊。
傳回值的內容與實作有關。它可能會在未來變更。
此方法僅用於偵錯 TracePoint
本身。
# File trace_point.rb, line 118 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 trace_point.rb, line 133 def self.trace(*events) Primitive.tracepoint_trace_s(events) end
公開實例方法
從事件傳回產生的繫結物件。
請注意,對於 :c_call
和 :c_return
事件,方法會傳回 nil
,因為 C 方法本身沒有繫結。
# File trace_point.rb, line 381 def binding Primitive.tracepoint_attr_binding end
傳回正在呼叫的方法的呼叫名稱
# File 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 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 trace_point.rb, line 296 def disable 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 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
追蹤的目前狀態
# File trace_point.rb, line 304 def enabled? Primitive.tracepoint_enabled_p end
已編譯的原始碼 (String
) 在 :script_compiled
事件的 *eval 方法上。如果從檔案載入,它會傳回 nil。
# File trace_point.rb, line 407 def eval_script Primitive.tracepoint_attr_eval_script end
事件類型
請參閱 TracePoint
的事件 以取得更多資訊。
# File trace_point.rb, line 311 def event Primitive.tracepoint_attr_event end
傳回包含人類可讀 TracePoint
狀態的字串。
# File trace_point.rb, line 105 def inspect Primitive.tracepoint_inspect end
在 :script_compiled
事件上由 RubyVM::InstructionSequence
執行個體表示的已編譯指令序列。
請注意,此方法是 MRI 特有的。
# File trace_point.rb, line 415 def instruction_sequence Primitive.tracepoint_attr_instruction_sequence end
事件的行號
# 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
傳回目前掛鉤所屬的方法或區塊的參數定義。格式與 Method#parameters
相同
# File trace_point.rb, line 327 def parameters Primitive.tracepoint_attr_parameters end
正在執行的檔案路徑
# File trace_point.rb, line 321 def path Primitive.tracepoint_attr_path end
在 :raise
事件引發的例外狀況值,或在 :rescue
事件中救援的例外狀況值。
# File trace_point.rb, line 401 def raised_exception Primitive.tracepoint_attr_raised_exception end
:return
、:c_return
和 :b_return
事件的傳回值
# File trace_point.rb, line 396 def return_value Primitive.tracepoint_attr_return_value end
在事件期間傳回追蹤物件
與下列相同,但它會傳回 :c_call
和 :c_return
事件的正確物件 (方法接收器)
trace.binding.eval('self')
# File trace_point.rb, line 391 def self Primitive.tracepoint_attr_self end