Class: Smith::Trace::OpenTelemetry

Inherits:
Object
  • Object
show all
Defined in:
lib/smith/trace/open_telemetry.rb

Constant Summary collapse

CONFIG_MAP =
{
  transition: :trace_transitions,
  tool_call: :trace_tool_calls,
  token_usage: :trace_token_usage,
  provider_call: :trace_provider_calls,
  cost: :trace_cost,
  normalizer_decision: :trace_normalizer
}.freeze
CONTENT_KEYS =
%i[content prompt response args result].freeze

Instance Method Summary collapse

Constructor Details

#initializeOpenTelemetry

Returns a new instance of OpenTelemetry.



17
18
19
20
21
22
23
24
25
26
# File 'lib/smith/trace/open_telemetry.rb', line 17

def initialize
  require "opentelemetry-api"
  @tracer = ::OpenTelemetry.tracer_provider.tracer("smith", Smith::VERSION)
rescue LoadError
  @tracer = nil
  Smith.config.logger&.warn(
    "Smith::Trace::OpenTelemetry requires the opentelemetry-api gem. " \
    "Add it to your Gemfile to enable OpenTelemetry tracing."
  )
end

Instance Method Details

#record(type:, data:) ⇒ Object

Smith trace events describe operations that already finished, so the span is created retroactively: when the event carries a duration (:tool_call seconds, :provider_call milliseconds) the span's start is backdated by it and the span duration is real; otherwise the span is an instant. Uses only the documented opentelemetry-api surface (Tracer#start_span with start_timestamp, Span#finish with end_timestamp) so any SDK the host installs applies.



35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/smith/trace/open_telemetry.rb', line 35

def record(type:, data:)
  return unless @tracer
  return unless type_enabled?(type)

  filtered = filter_content(data)
  finished_at = Time.now
  span = @tracer.start_span("smith.#{type}", start_timestamp: span_start(filtered, finished_at))
  begin
    apply_attributes(span, filtered)
  ensure
    span.finish(end_timestamp: finished_at)
  end
end