Module: TypedOperation::Instrumentation

Defined in:
lib/typed_operation/instrumentation.rb,
lib/typed_operation/instrumentation/trace.rb,
lib/typed_operation/instrumentation/tree_formatter.rb

Overview

Provides runtime tracing and debugging capabilities for operations.

Usage:

# Trace a single operation call
result = MyOperation.explain(param: value)
# Prints execution tree to stdout, returns the operation result

# Trace with partial application
result = MyOperation.with(partial: value).explain(rest: value)

# Trace a block of code (captures all instrumented operations)
TypedOperation::Instrumentation.explaining do
  MyOperation.call(params)
  AnotherOperation.call(other_params)
end

# Configure output and color
TypedOperation::Instrumentation.with_output(my_io, color: false) do
  MyOperation.explain(param: value)
end

Defined Under Namespace

Modules: Explainable, Traceable Classes: BlockExecution, Trace, TreeFormatter

Constant Summary collapse

THREAD_KEY =

: Symbol

:typed_operation_trace_stack
CHAIN_CONTEXT_KEY =

: Symbol

:typed_operation_chain_context
OUTPUT_KEY =

: Symbol

:typed_operation_output
COLOR_KEY =

: Symbol

:typed_operation_color

Class Method Summary collapse

Class Method Details

.clear_trace!Object

: () -> void



113
114
115
116
# File 'lib/typed_operation/instrumentation.rb', line 113

def clear_trace!
  Thread.current[THREAD_KEY] = nil
  Thread.current[CHAIN_CONTEXT_KEY] = nil
end

.colorObject

: () -> bool



81
82
83
84
# File 'lib/typed_operation/instrumentation.rb', line 81

def color
  val = Thread.current[COLOR_KEY]
  val.nil? || val
end

.current_traceObject

: () -> Trace?



87
88
89
90
# File 'lib/typed_operation/instrumentation.rb', line 87

def current_trace
  stack = Thread.current[THREAD_KEY]
  stack&.last
end

.explaining(&block) ⇒ Object

Execute a block with tracing enabled, printing the trace tree afterward. : [T] () { () -> T } -> T



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/typed_operation/instrumentation.rb', line 51

def explaining(&block)
  trace_root = Trace.new(operation_class: BlockExecution, params: {})
  push_trace(trace_root)

  result = nil
  exception = nil
  begin
    result = block.call
  rescue => e
    exception = e
  end

  trace_root.finish!(result: result, exception: exception)
  pop_trace

  formatter = TreeFormatter.new(color: color)
  trace_root.children.each do |child_trace|
    output.puts formatter.format(child_trace)
  end

  raise exception if exception
  result
end

.outputObject

: () -> IO



76
77
78
# File 'lib/typed_operation/instrumentation.rb', line 76

def output
  Thread.current[OUTPUT_KEY] || $stdout
end

.pop_traceObject

: () -> Trace?



106
107
108
109
110
# File 'lib/typed_operation/instrumentation.rb', line 106

def pop_trace
  stack = Thread.current[THREAD_KEY]
  stack&.pop
  Thread.current[THREAD_KEY] = nil if stack&.empty?
end

.push_trace(trace) ⇒ Object

: (Trace) -> void



98
99
100
101
102
103
# File 'lib/typed_operation/instrumentation.rb', line 98

def push_trace(trace)
  Thread.current[THREAD_KEY] ||= []
  parent = current_trace
  parent&.add_child(trace)
  Thread.current[THREAD_KEY].push(trace)
end

.set_chain_context(pass_mode:, extracted_params: nil, fallback_used: false) ⇒ Object

: (pass_mode: Symbol, ?extracted_params: Array?, ?fallback_used: bool) -> void



119
120
121
122
123
124
125
# File 'lib/typed_operation/instrumentation.rb', line 119

def set_chain_context(pass_mode:, extracted_params: nil, fallback_used: false)
  Thread.current[CHAIN_CONTEXT_KEY] = {
    pass_mode: pass_mode,
    extracted_params: extracted_params,
    fallback_used: fallback_used
  }
end

.take_chain_contextObject

: () -> Hash[Symbol, untyped]?



128
129
130
131
132
# File 'lib/typed_operation/instrumentation.rb', line 128

def take_chain_context
  ctx = Thread.current[CHAIN_CONTEXT_KEY]
  Thread.current[CHAIN_CONTEXT_KEY] = nil
  ctx
end

.tracing?Boolean

: () -> bool

Returns:

  • (Boolean)


93
94
95
# File 'lib/typed_operation/instrumentation.rb', line 93

def tracing?
  !current_trace.nil?
end

.with_output(io, color: nil, &block) ⇒ Object

Execute a block with custom output and color settings. : [T] (IO, ?color: bool?) { () -> T } -> T



38
39
40
41
42
43
44
45
46
47
# File 'lib/typed_operation/instrumentation.rb', line 38

def with_output(io, color: nil, &block)
  old_output = Thread.current[OUTPUT_KEY]
  old_color = Thread.current[COLOR_KEY]
  Thread.current[OUTPUT_KEY] = io
  Thread.current[COLOR_KEY] = color
  yield
ensure
  Thread.current[OUTPUT_KEY] = old_output
  Thread.current[COLOR_KEY] = old_color
end