Class: ActiveAgents::Telemetry::Span
- Inherits:
-
Object
- Object
- ActiveAgents::Telemetry::Span
- Defined in:
- lib/activeagents/telemetry/span.rb
Overview
A single operation inside a trace, serialized to the /v1/traces wire
format. Adapters build these rather than hand-rolling hashes, so a span
from the RubyLLM adapter and a span from any future adapter are shaped
identically on the wire.
Constant Summary collapse
- TYPES =
%w[root prompt llm tool thinking embedding error].freeze
- OK =
"OK"- ERROR =
"ERROR"- UNSET =
"UNSET"- ZERO_TOKENS =
{ "input" => 0, "output" => 0, "thinking" => 0, "total" => 0 }.freeze
Instance Attribute Summary collapse
-
#attributes ⇒ Object
readonly
Returns the value of attribute attributes.
-
#children ⇒ Object
readonly
Returns the value of attribute children.
-
#end_time ⇒ Object
Returns the value of attribute end_time.
-
#events ⇒ Object
readonly
Returns the value of attribute events.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#parent_span_id ⇒ Object
Returns the value of attribute parent_span_id.
-
#span_id ⇒ Object
readonly
Returns the value of attribute span_id.
-
#start_time ⇒ Object
Returns the value of attribute start_time.
-
#status ⇒ Object
Returns the value of attribute status.
-
#status_message ⇒ Object
readonly
Returns the value of attribute status_message.
-
#trace_id ⇒ Object
Returns the value of attribute trace_id.
-
#type ⇒ Object
readonly
Returns the value of attribute type.
Instance Method Summary collapse
- #add_event(name, attributes = {}) ⇒ Object
-
#add_span(name, type: "root", **options) ⇒ Object
Builds a child span sharing this span's trace.
-
#add_tokens(other) ⇒ Object
Adds another span's token counts to this one — how a turn-level llm span accumulates the rounds it covers.
- #duration_ms ⇒ Object
- #finish(at: nil) ⇒ Object
- #finished? ⇒ Boolean
-
#initialize(name, type:, trace_id: nil, parent_span_id: nil, span_id: nil, attributes: {}, start_time: nil) ⇒ Span
constructor
A new instance of Span.
-
#measure ⇒ Object
Runs the block, recording its outcome and timing on the span.
-
#record_error(error, message_limit: 200) ⇒ Object
Records an error without ever putting a backtrace or an untruncated message on the wire — telemetry payloads leave the app's trust boundary.
- #set_attribute(key, value) ⇒ Object
- #set_attributes(attrs) ⇒ Object
- #set_status(code, message = nil) ⇒ Object
- #set_tokens(input: 0, output: 0, thinking: 0) ⇒ Object
- #to_h ⇒ Object
- #tokens ⇒ Object
Constructor Details
#initialize(name, type:, trace_id: nil, parent_span_id: nil, span_id: nil, attributes: {}, start_time: nil) ⇒ Span
Returns a new instance of Span.
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/activeagents/telemetry/span.rb', line 23 def initialize(name, type:, trace_id: nil, parent_span_id: nil, span_id: nil, attributes: {}, start_time: nil) @span_id = span_id || SecureRandom.hex(8) @trace_id = trace_id @parent_span_id = parent_span_id @name = name.to_s @type = type.to_s @attributes = stringify(attributes) @start_time = start_time || Time.now @end_time = nil @status = UNSET @status_message = nil @tokens = ZERO_TOKENS.dup @events = [] @children = [] end |
Instance Attribute Details
#attributes ⇒ Object (readonly)
Returns the value of attribute attributes.
20 21 22 |
# File 'lib/activeagents/telemetry/span.rb', line 20 def attributes @attributes end |
#children ⇒ Object (readonly)
Returns the value of attribute children.
20 21 22 |
# File 'lib/activeagents/telemetry/span.rb', line 20 def children @children end |
#end_time ⇒ Object
Returns the value of attribute end_time.
21 22 23 |
# File 'lib/activeagents/telemetry/span.rb', line 21 def end_time @end_time end |
#events ⇒ Object (readonly)
Returns the value of attribute events.
20 21 22 |
# File 'lib/activeagents/telemetry/span.rb', line 20 def events @events end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
20 21 22 |
# File 'lib/activeagents/telemetry/span.rb', line 20 def name @name end |
#parent_span_id ⇒ Object
Returns the value of attribute parent_span_id.
21 22 23 |
# File 'lib/activeagents/telemetry/span.rb', line 21 def parent_span_id @parent_span_id end |
#span_id ⇒ Object (readonly)
Returns the value of attribute span_id.
20 21 22 |
# File 'lib/activeagents/telemetry/span.rb', line 20 def span_id @span_id end |
#start_time ⇒ Object
Returns the value of attribute start_time.
21 22 23 |
# File 'lib/activeagents/telemetry/span.rb', line 21 def start_time @start_time end |
#status ⇒ Object
Returns the value of attribute status.
21 22 23 |
# File 'lib/activeagents/telemetry/span.rb', line 21 def status @status end |
#status_message ⇒ Object (readonly)
Returns the value of attribute status_message.
20 21 22 |
# File 'lib/activeagents/telemetry/span.rb', line 20 def @status_message end |
#trace_id ⇒ Object
Returns the value of attribute trace_id.
39 40 41 |
# File 'lib/activeagents/telemetry/span.rb', line 39 def trace_id @trace_id end |
#type ⇒ Object (readonly)
Returns the value of attribute type.
20 21 22 |
# File 'lib/activeagents/telemetry/span.rb', line 20 def type @type end |
Instance Method Details
#add_event(name, attributes = {}) ⇒ Object
89 90 91 92 |
# File 'lib/activeagents/telemetry/span.rb', line 89 def add_event(name, attributes = {}) @events << { "name" => name.to_s, "timestamp" => iso8601(Time.now), "attributes" => stringify(attributes) } self end |
#add_span(name, type: "root", **options) ⇒ Object
Builds a child span sharing this span's trace. Instrumentation that holds only a span — not the enclosing trace — nests through this; Trace#to_h flattens the tree back out for the wire.
51 52 53 54 55 |
# File 'lib/activeagents/telemetry/span.rb', line 51 def add_span(name, type: "root", **) child = Span.new(name, type: type, trace_id: trace_id, parent_span_id: span_id, **) @children << child child end |
#add_tokens(other) ⇒ Object
Adds another span's token counts to this one — how a turn-level llm span accumulates the rounds it covers.
83 84 85 86 87 |
# File 'lib/activeagents/telemetry/span.rb', line 83 def add_tokens(other) counts = other.respond_to?(:tokens) ? other.tokens : other @tokens = @tokens.merge(stringify(counts)) { |_key, carried, added| carried.to_i + added.to_i } self end |
#duration_ms ⇒ Object
121 122 123 124 125 |
# File 'lib/activeagents/telemetry/span.rb', line 121 def duration_ms return nil unless finished? ((@end_time - @start_time) * 1000).round(2) end |
#finish(at: nil) ⇒ Object
111 112 113 114 115 |
# File 'lib/activeagents/telemetry/span.rb', line 111 def finish(at: nil) @end_time = at || Time.now @status = OK if @status == UNSET self end |
#finished? ⇒ Boolean
117 118 119 |
# File 'lib/activeagents/telemetry/span.rb', line 117 def finished? !@end_time.nil? end |
#measure ⇒ Object
Runs the block, recording its outcome and timing on the span.
146 147 148 149 150 151 152 153 154 155 |
# File 'lib/activeagents/telemetry/span.rb', line 146 def measure result = yield(self) set_status(:ok) if @status == UNSET result rescue StandardError => e record_error(e) raise ensure finish end |
#record_error(error, message_limit: 200) ⇒ Object
Records an error without ever putting a backtrace or an untruncated message on the wire — telemetry payloads leave the app's trust boundary.
103 104 105 106 107 108 109 |
# File 'lib/activeagents/telemetry/span.rb', line 103 def record_error(error, message_limit: 200) @status = ERROR @status_message = truncate(error..to_s, ) set_attribute("error.type", error.class.name) set_attribute("error.message", truncate(error..to_s, )) self end |
#set_attribute(key, value) ⇒ Object
57 58 59 60 |
# File 'lib/activeagents/telemetry/span.rb', line 57 def set_attribute(key, value) @attributes[key.to_s] = value self end |
#set_attributes(attrs) ⇒ Object
62 63 64 65 |
# File 'lib/activeagents/telemetry/span.rb', line 62 def set_attributes(attrs) @attributes.merge!(stringify(attrs)) self end |
#set_status(code, message = nil) ⇒ Object
95 96 97 98 99 |
# File 'lib/activeagents/telemetry/span.rb', line 95 def set_status(code, = nil) @status = { ok: OK, error: ERROR, unset: UNSET }.fetch(code.to_s.downcase.to_sym, UNSET) @status_message = self end |
#set_tokens(input: 0, output: 0, thinking: 0) ⇒ Object
67 68 69 70 71 72 73 74 75 |
# File 'lib/activeagents/telemetry/span.rb', line 67 def set_tokens(input: 0, output: 0, thinking: 0) @tokens = { "input" => input.to_i, "output" => output.to_i, "thinking" => thinking.to_i, "total" => input.to_i + output.to_i + thinking.to_i } self end |
#to_h ⇒ Object
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/activeagents/telemetry/span.rb', line 127 def to_h { "span_id" => span_id, "trace_id" => trace_id, "parent_span_id" => parent_span_id, "name" => name, "type" => type, "start_time" => iso8601(start_time), "end_time" => end_time ? iso8601(end_time) : nil, "duration_ms" => duration_ms, "status" => status, "status_message" => , "attributes" => attributes, "tokens" => tokens, "events" => events } end |
#tokens ⇒ Object
77 78 79 |
# File 'lib/activeagents/telemetry/span.rb', line 77 def tokens @tokens.dup end |