Class: ClaudeAgentSDK::Instrumentation::OTelObserver
- Inherits:
-
Object
- Object
- ClaudeAgentSDK::Instrumentation::OTelObserver
- Includes:
- Observer
- Defined in:
- lib/claude_agent_sdk/instrumentation/otel.rb
Overview
OpenTelemetry observer that emits spans for Claude Agent SDK messages.
Uses standard gen_ai.* semantic conventions recognized by Langfuse, Datadog, Jaeger, and other OTel-compatible backends.
Requires the ‘opentelemetry-api` gem at runtime. Users must configure `opentelemetry-sdk` and an exporter (e.g., `opentelemetry-exporter-otlp`) themselves before creating this observer.
Constant Summary collapse
- TRACER_NAME =
'claude_agent_sdk'- MAX_ATTRIBUTE_LENGTH =
4096
Instance Method Summary collapse
-
#initialize(tracer_name: TRACER_NAME, **default_attributes) ⇒ OTelObserver
constructor
A new instance of OTelObserver.
- #on_close ⇒ Object
-
#on_error(error) ⇒ Object
Recording-only by design: a Client session can survive an error (the user may rescue one bad message and keep receiving), so finishing here would orphan later spans and break the next turn.
- #on_message(message) ⇒ Object
- #on_user_prompt(prompt) ⇒ Object
Constructor Details
#initialize(tracer_name: TRACER_NAME, **default_attributes) ⇒ OTelObserver
Returns a new instance of OTelObserver.
43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/claude_agent_sdk/instrumentation/otel.rb', line 43 def initialize(tracer_name: TRACER_NAME, **default_attributes) require 'opentelemetry' @tracer = OpenTelemetry.tracer_provider.tracer( tracer_name, defined?(ClaudeAgentSDK::VERSION) ? ClaudeAgentSDK::VERSION : '0.0.0' ) @default_attributes = default_attributes @root_span = nil @root_context = nil @tool_spans = {} # tool_use_id => span @first_user_input = nil # capture first user prompt for trace input @last_assistant_text = nil # capture last assistant text for trace output end |
Instance Method Details
#on_close ⇒ Object
96 97 98 99 |
# File 'lib/claude_agent_sdk/instrumentation/otel.rb', line 96 def on_close finish_open_spans reset_session_buffers end |
#on_error(error) ⇒ Object
Recording-only by design: a Client session can survive an error (the user may rescue one bad message and keep receiving), so finishing here would orphan later spans and break the next turn. Finish ownership stays with end_trace/on_close; start_trace also finishes any dangling span from a previous trace as the never-disconnected backstop.
89 90 91 92 93 94 |
# File 'lib/claude_agent_sdk/instrumentation/otel.rb', line 89 def on_error(error) return unless @root_span @root_span.record_exception(error) @root_span.status = OpenTelemetry::Trace::Status.error(error.) end |
#on_message(message) ⇒ Object
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/claude_agent_sdk/instrumentation/otel.rb', line 65 def () case when ClaudeAgentSDK::InitMessage start_trace() when ClaudeAgentSDK::AssistantMessage handle_assistant() when ClaudeAgentSDK::UserMessage handle_user() when ClaudeAgentSDK::ResultMessage end_trace() when ClaudeAgentSDK::APIRetryMessage record_retry_event() when ClaudeAgentSDK::RateLimitEvent record_rate_limit_event() when ClaudeAgentSDK::ToolProgressMessage record_tool_progress_event() end end |
#on_user_prompt(prompt) ⇒ Object
57 58 59 60 61 62 63 |
# File 'lib/claude_agent_sdk/instrumentation/otel.rb', line 57 def on_user_prompt(prompt) return if @first_user_input # only capture the first prompt @first_user_input = prompt.to_s # If root span already exists, set immediately; otherwise start_trace will apply it @root_span&.set_attribute('input.value', truncate(@first_user_input)) unless @first_user_input.empty? end |