Class: RubyMethodTracer::CallTree
- Inherits:
-
Object
- Object
- RubyMethodTracer::CallTree
- Defined in:
- lib/ruby_method_tracer/call_tree.rb
Overview
CallTree manages the hierarchical structure of method calls, tracking parent-child relationships and call depths.
It uses a per-thread stack to manage nested calls and builds a tree structure showing the complete call hierarchy.
Note: @calls and @root_calls are shared across threads and protected by a Mutex. The call stack is stored in thread-local storage so that concurrent callers each maintain their own independent call depth.
Instance Attribute Summary collapse
-
#calls ⇒ Object
readonly
Returns the value of attribute calls.
-
#root_calls ⇒ Object
readonly
Returns the value of attribute root_calls.
Instance Method Summary collapse
-
#call_hierarchy ⇒ Array<Hash>
Get call hierarchy as nested structure.
-
#clear ⇒ Object
Clear all recorded calls and reset state.
-
#current_depth ⇒ Integer
Get the current call depth for the calling thread.
-
#empty? ⇒ Boolean
Check if the current thread has no active calls.
-
#end_call(status = :success, error = nil) ⇒ Hash?
End tracking a method call.
-
#initialize ⇒ CallTree
constructor
A new instance of CallTree.
-
#start_call(method_name) ⇒ Hash
Start tracking a method call.
-
#statistics ⇒ Hash
Calculate statistics from recorded calls.
Constructor Details
#initialize ⇒ CallTree
Returns a new instance of CallTree.
16 17 18 19 20 21 |
# File 'lib/ruby_method_tracer/call_tree.rb', line 16 def initialize @calls = [] # All recorded calls (flat list, shared) @root_calls = [] # Top-level calls (depth 0, shared) @lock = Mutex.new # Protects @calls and @root_calls @thread_key = :"__ruby_method_tracer_call_stack_#{object_id}" # per-instance thread-local key end |
Instance Attribute Details
#calls ⇒ Object (readonly)
Returns the value of attribute calls.
14 15 16 |
# File 'lib/ruby_method_tracer/call_tree.rb', line 14 def calls @calls end |
#root_calls ⇒ Object (readonly)
Returns the value of attribute root_calls.
14 15 16 |
# File 'lib/ruby_method_tracer/call_tree.rb', line 14 def root_calls @root_calls end |
Instance Method Details
#call_hierarchy ⇒ Array<Hash>
Get call hierarchy as nested structure
79 80 81 |
# File 'lib/ruby_method_tracer/call_tree.rb', line 79 def call_hierarchy @lock.synchronize { @root_calls.dup } end |
#clear ⇒ Object
Clear all recorded calls and reset state
Note: only the current thread’s call stack is cleared; other threads that are mid-trace retain their stacks.
108 109 110 111 112 113 114 |
# File 'lib/ruby_method_tracer/call_tree.rb', line 108 def clear @lock.synchronize do @calls.clear @root_calls.clear end thread_call_stack.clear end |
#current_depth ⇒ Integer
Get the current call depth for the calling thread
72 73 74 |
# File 'lib/ruby_method_tracer/call_tree.rb', line 72 def current_depth thread_call_stack.size end |
#empty? ⇒ Boolean
Check if the current thread has no active calls
119 120 121 |
# File 'lib/ruby_method_tracer/call_tree.rb', line 119 def empty? thread_call_stack.empty? end |
#end_call(status = :success, error = nil) ⇒ Hash?
End tracking a method call
56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/ruby_method_tracer/call_tree.rb', line 56 def end_call(status = :success, error = nil) stack = thread_call_stack return nil if stack.empty? call_record = stack.pop call_record[:status] = status call_record[:error] = error call_record[:execution_time] = monotonic_time - call_record[:start_time] @lock.synchronize { @calls << call_record } call_record end |
#start_call(method_name) ⇒ Hash
Start tracking a method call
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/ruby_method_tracer/call_tree.rb', line 27 def start_call(method_name) stack = thread_call_stack call_record = { method_name: method_name, start_time: monotonic_time, depth: stack.size, children: [], status: nil, error: nil, execution_time: nil, timestamp: Time.now } # Add as child to parent if we're nested stack.last[:children] << call_record if stack.any? # Track root-level calls (lock required since @root_calls is shared) @lock.synchronize { @root_calls << call_record } if stack.empty? stack.push(call_record) call_record end |
#statistics ⇒ Hash
Calculate statistics from recorded calls
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/ruby_method_tracer/call_tree.rb', line 86 def statistics @lock.synchronize do return default_statistics if @calls.empty? method_stats = calculate_method_stats { total_calls: @calls.size, total_time: @calls.sum { |c| c[:execution_time] }, unique_methods: method_stats.size, slowest_methods: slowest_methods(method_stats), most_called_methods: most_called_methods(method_stats), average_time_per_method: average_times(method_stats), max_depth: @calls.map { |c| c[:depth] }.max || 0 } end end |