Class: LittleGhost::Tracing::OpenTelemetry
- Inherits:
-
Instrumentation::Subscriber
- Object
- Instrumentation::Subscriber
- LittleGhost::Tracing::OpenTelemetry
- Defined in:
- lib/little_ghost/tracing/open_telemetry.rb
Overview
OpenTelemetry turns LittleGhost lifecycle notifications into GenAI spans and events. It brings agents, model calls, tools, workflows, and token usage into the same traces as the rest of an application.
LittleGhost.configure do |config|
config.instrument LittleGhost::Tracing::OpenTelemetry.new
end
LittleGhost depends only on opentelemetry-api. Install and configure the
desired SDK, processors, and exporters before registering this subscriber.
Content and trust
Prompts, responses, messages, tool arguments, and exception content are omitted by default. They appear only when Instrumentation has an explicit, scrubbed Support::ContentCapture policy.
Constant Summary collapse
- ATTRIBUTE_NAMES =
{ agent_id: "gen_ai.agent.id", agent_name: "gen_ai.agent.name", model_id: "gen_ai.request.model", model_provider: "gen_ai.provider.name", response_id: "gen_ai.response.id", response_model: "gen_ai.response.model", finish_reasons: "gen_ai.response.finish_reasons", input_tokens: "gen_ai.usage.input_tokens", output_tokens: "gen_ai.usage.output_tokens", cache_read_tokens: "gen_ai.usage.cache_read.input_tokens", cache_write_tokens: "gen_ai.usage.cache_creation.input_tokens", reasoning_tokens: "gen_ai.usage.reasoning.output_tokens", time_to_first_token: "gen_ai.response.time_to_first_chunk", session_id: "gen_ai.conversation.id", tool_name: "gen_ai.tool.name", tool_type: "gen_ai.tool.type", tool_call_id: "gen_ai.tool.call.id", workflow_name: "gen_ai.workflow.name", assembly_id: "little_ghost.assembly.id", assembly_kind: "little_ghost.assembly.kind", http_response_status_code: "http.response.status_code", error_class: "error.type", error_type: "error.type" }.freeze
- OPERATIONS =
:nodoc:
{ agent: "invoke_agent", agent_turn: "agent_turn", model: "chat", run: "invoke_agent", runtime: "runtime_startup", session_store: "session_store", subagent: "invoke_agent", assembly_step: "execute_assembly_step", tool: "execute_tool", workflow: "invoke_workflow", swarm: "invoke_swarm", graph: "invoke_graph", assembly: "invoke_assembly", generation: "chat", embedding: "embeddings" }.freeze
- REQUEST_SETTING_ATTRIBUTES =
:nodoc:
{ frequency_penalty: "gen_ai.request.frequency_penalty", max_tokens: "gen_ai.request.max_tokens", max_output_tokens: "gen_ai.request.max_tokens", presence_penalty: "gen_ai.request.presence_penalty", seed: "gen_ai.request.seed", temperature: "gen_ai.request.temperature", top_k: "gen_ai.request.top_k", top_p: "gen_ai.request.top_p" }.freeze
- CONTENT_KEYS =
:nodoc:
%w[arguments content input input_text message output output_text prompt response text].freeze
- SENSITIVE_KEY =
:nodoc:
/(authorization|api[_-]?key|credential|password|secret|(?:^|[_-])token(?:$|[_-])|cookie|private[_-]?key)/i- MAX_ATTRIBUTE_LENGTH =
:nodoc:
1_024
Instance Method Summary collapse
-
#emit(name, attributes) ⇒ Object
Adds a structured event to the correlated active span.
-
#finish(name, attributes) ⇒ Object
Finishes the span correlated by operation ID.
-
#flush(timeout: nil) ⇒ Object
Flushes through the configured tracer provider when supported.
-
#initialize(tracer: nil) ⇒ OpenTelemetry
constructor
Uses
traceror the global tracer provider. -
#shutdown(timeout: nil) ⇒ Object
Finishes spans still owned by this subscriber.
-
#start(name, attributes) ⇒ Object
Starts a span for a lifecycle operation.
-
#trace_context(operation_id: nil) ⇒ Object
Supplies W3C propagation fields for an active operation when known.
-
#with_span(name, attributes:, parent_operation_id: nil) ⇒ Object
Wraps a block in a standalone internal span.
Constructor Details
#initialize(tracer: nil) ⇒ OpenTelemetry
Uses tracer or the global tracer provider.
83 84 85 86 87 |
# File 'lib/little_ghost/tracing/open_telemetry.rb', line 83 def initialize(tracer: nil) @tracer = tracer @entries = {} @mutex = Mutex.new end |
Instance Method Details
#emit(name, attributes) ⇒ Object
Adds a structured event to the correlated active span.
100 101 102 |
# File 'lib/little_ghost/tracing/open_telemetry.rb', line 100 def emit(name, attributes) add_event(name.to_sym, prepare_attributes(:emit, name.to_sym, attributes)) end |
#finish(name, attributes) ⇒ Object
Finishes the span correlated by operation ID.
95 96 97 |
# File 'lib/little_ghost/tracing/open_telemetry.rb', line 95 def finish(name, attributes) finish_span(name.to_sym, prepare_attributes(:finish, name.to_sym, attributes)) end |
#flush(timeout: nil) ⇒ Object
Flushes through the configured tracer provider when supported.
137 138 139 140 |
# File 'lib/little_ghost/tracing/open_telemetry.rb', line 137 def flush(timeout: nil) provider = ::OpenTelemetry.tracer_provider provider.force_flush(timeout:) if provider.respond_to?(:force_flush) end |
#shutdown(timeout: nil) ⇒ Object
Finishes spans still owned by this subscriber.
143 144 145 146 147 148 149 150 |
# File 'lib/little_ghost/tracing/open_telemetry.rb', line 143 def shutdown(timeout: nil) spans = @mutex.synchronize do current = @entries.values.map { |entry| entry.fetch(:span) }.uniq @entries = {} current end spans.each(&:finish) end |
#start(name, attributes) ⇒ Object
Starts a span for a lifecycle operation.
90 91 92 |
# File 'lib/little_ghost/tracing/open_telemetry.rb', line 90 def start(name, attributes) start_span(name.to_sym, prepare_attributes(:start, name.to_sym, attributes)) end |
#trace_context(operation_id: nil) ⇒ Object
Supplies W3C propagation fields for an active operation when known.
105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/little_ghost/tracing/open_telemetry.rb', line 105 def trace_context(operation_id: nil, **) span = @mutex.synchronize { @entries.dig(operation_id, :span) } context = span&.context return {} unless context&.valid? carrier = {} trace_context_propagator.inject( carrier, context: ::OpenTelemetry::Trace.context_with_span(span) ) carrier.slice("traceparent", "tracestate").merge(trace_id: context.hex_trace_id) rescue context&.valid? ? {trace_id: context.hex_trace_id} : {} end |
#with_span(name, attributes:, parent_operation_id: nil) ⇒ Object
Wraps a block in a standalone internal span. Prefer lifecycle Instrumentation methods for normal framework operations.
122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/little_ghost/tracing/open_telemetry.rb', line 122 def with_span(name, attributes:, parent_operation_id: nil) parent = @mutex.synchronize { @entries[parent_operation_id] } parent_context = parent && ::OpenTelemetry::Trace.context_with_span(parent.fetch(:span)) = {kind: :internal, attributes:} [:with_parent] = parent_context if parent_context span = tracer.start_span(name, **) yield span rescue => error span.status = ::OpenTelemetry::Trace::Status.error(error.class.name) if span raise ensure span&.finish end |