Module: LangsmithrbRails::OTEL

Defined in:
lib/langsmithrb_rails/otel.rb,
lib/langsmithrb_rails/otel/exporter.rb

Overview

OpenTelemetry integration for LangSmith

Defined Under Namespace

Classes: Exporter

Class Method Summary collapse

Class Method Details

.init(api_key: nil, api_url: nil, service_name: "langsmithrb-rails", service_version: LangsmithrbRails::VERSION) ⇒ Boolean

Initialize OpenTelemetry integration



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/langsmithrb_rails/otel.rb', line 15

def init(api_key: nil, api_url: nil, service_name: "langsmithrb-rails", service_version: LangsmithrbRails::VERSION)
  return false unless otel_available?

  require "opentelemetry/sdk"
  require "opentelemetry/exporter/otlp"
  require "opentelemetry/instrumentation/all"

  # Create LangSmith exporter
  langsmith_exporter = Exporter.new(api_key: api_key, api_url: api_url)

  # Configure OpenTelemetry
  OpenTelemetry::SDK.configure do |c|
    c.service_name = service_name
    c.service_version = service_version
    
    # Add LangSmith exporter
    c.add_span_processor(
      OpenTelemetry::SDK::Trace::Export::SimpleSpanProcessor.new(langsmith_exporter)
    )
    
    # Use batch processor for better performance
    c.add_span_processor(
      OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(
        langsmith_exporter,
        max_queue_size: 1000,
        max_export_batch_size: 100,
        schedule_delay_millis: 5000
      )
    )
    
    # Install all available instrumentation
    c.use_all()
  end

  true
rescue => e
  LangsmithrbRails.logger.error("Failed to initialize OpenTelemetry: #{e.message}")
  false
end

.otel_available?Boolean

Check if OpenTelemetry is available



118
119
120
121
122
123
124
125
126
# File 'lib/langsmithrb_rails/otel.rb', line 118

def otel_available?
  @otel_available ||= begin
    require "opentelemetry"
    require "opentelemetry/sdk"
    true
  rescue LoadError
    false
  end
end

.otel_enabled?Boolean

Check if OpenTelemetry is enabled



130
131
132
# File 'lib/langsmithrb_rails/otel.rb', line 130

def otel_enabled?
  Config[:otel_enabled]
end

.trace(name, attributes: {}, kind: :internal) { ... } ⇒ Object

Create a traced span

Yields:

  • Block to execute within the span



61
62
63
64
65
66
67
# File 'lib/langsmithrb_rails/otel.rb', line 61

def trace(name, attributes: {}, kind: :internal, &block)
  return yield unless otel_available? && otel_enabled?

  tracer = OpenTelemetry.tracer_provider.tracer("langsmithrb_rails", LangsmithrbRails::VERSION)
  
  tracer.in_span(name, attributes: attributes, kind: kind, &block)
end

.trace_llm(name, inputs:, run_type: "llm", project_name: nil, tags: []) { ... } ⇒ Object

Create a traced span for an LLM operation

Yields:

  • Block to execute within the span



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/langsmithrb_rails/otel.rb', line 77

def trace_llm(name, inputs:, run_type: "llm", project_name: nil, tags: [], &block)
  return yield unless otel_available? && otel_enabled?

  attributes = {
    inputs: inputs.to_json,
    run_type: run_type
  }
  
  if project_name
    attributes[:project_name] = project_name
  end
  
  if tags.any?
    attributes[:tags] = tags.to_json
  end
  
  trace(name, attributes: attributes) do |span|
    begin
      result = yield
      
      # Add outputs to span
      if result
        span.add_attributes(outputs: { result: result }.to_json)
      end
      
      result
    rescue => e
      # Add error to span
      if span.respond_to?(:record_exception)
        span.record_exception(e)
        if defined?(OpenTelemetry::Trace::Status)
          span.status = OpenTelemetry::Trace::Status.error(e.message)
        end
      end
      raise e
    end
  end
end