Module: Foam::Ruby::OtelSetup

Defined in:
lib/foam/ruby/otel_setup.rb

Constant Summary collapse

INSTRUMENTATIONS =
%w[
  opentelemetry-instrumentation-rack
  opentelemetry-instrumentation-rails
  opentelemetry-instrumentation-action_pack
  opentelemetry-instrumentation-action_view
  opentelemetry-instrumentation-action_mailer
  opentelemetry-instrumentation-active_record
  opentelemetry-instrumentation-active_support
  opentelemetry-instrumentation-active_job
  opentelemetry-instrumentation-active_storage
  opentelemetry-instrumentation-concurrent_ruby
].freeze

Class Method Summary collapse

Class Method Details

.configure!(config) ⇒ Object



27
28
29
30
31
# File 'lib/foam/ruby/otel_setup.rb', line 27

def configure!(config)
  configure_traces(config)
  configure_logs(config)
  register_at_exit_flush!
end

.configure_logs(config) ⇒ Object



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/foam/ruby/otel_setup.rb', line 96

def configure_logs(config)
  @foam_log_processor = OpenTelemetry::SDK::Logs::Export::BatchLogRecordProcessor.new(
    OpenTelemetry::Exporter::OTLP::Logs::LogsExporter.new(
      endpoint: config.logs_endpoint,
      headers: config.otel_headers
    )
  )

  existing = OpenTelemetry.logger_provider
  if existing.is_a?(OpenTelemetry::SDK::Logs::LoggerProvider)
    existing.add_log_record_processor(@foam_log_processor)
  else
    resource = OpenTelemetry::SDK::Resources::Resource.create(
      "service.name" => config.service_name,
      "deployment.environment" => ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "production"
    )
    provider = OpenTelemetry::SDK::Logs::LoggerProvider.new(resource: resource)
    provider.add_log_record_processor(@foam_log_processor)
    OpenTelemetry.logger_provider = provider
  end

  @attached_logger_provider = OpenTelemetry.logger_provider
end

.configure_traces(config) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/foam/ruby/otel_setup.rb', line 41

def configure_traces(config)
  require_instrumentations!
  @foam_span_processor = OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(
    OpenTelemetry::Exporter::OTLP::Exporter.new(
      endpoint: config.traces_endpoint,
      headers: config.otel_headers
    )
  )

  existing = OpenTelemetry.tracer_provider
  if existing.is_a?(OpenTelemetry::SDK::Trace::TracerProvider)
    existing.add_span_processor(@foam_span_processor)
    install_instrumentations!
  else
    OpenTelemetry::SDK.configure do |c|
      c.service_name = config.service_name
      c.add_span_processor(@foam_span_processor)
      c.use_all
    end
  end

  @attached_provider = OpenTelemetry.tracer_provider
end

.ensure_log_processor_attached!Object



120
121
122
123
124
125
126
127
128
129
# File 'lib/foam/ruby/otel_setup.rb', line 120

def ensure_log_processor_attached!
  return unless @foam_log_processor

  current = OpenTelemetry.logger_provider
  return if current.equal?(@attached_logger_provider)
  return unless current.is_a?(OpenTelemetry::SDK::Logs::LoggerProvider)

  current.add_log_record_processor(@foam_log_processor)
  @attached_logger_provider = current
end

.ensure_processor_attached!Object



85
86
87
88
89
90
91
92
93
94
# File 'lib/foam/ruby/otel_setup.rb', line 85

def ensure_processor_attached!
  return unless @foam_span_processor

  current = OpenTelemetry.tracer_provider
  return if current.equal?(@attached_provider)
  return unless current.is_a?(OpenTelemetry::SDK::Trace::TracerProvider)

  current.add_span_processor(@foam_span_processor)
  @attached_provider = current
end

.install_instrumentations!Object



65
66
67
68
69
70
71
72
# File 'lib/foam/ruby/otel_setup.rb', line 65

def install_instrumentations!
  registry = OpenTelemetry::Instrumentation.registry
  return unless registry

  registry.each do |instrumentation|
    instrumentation.install unless instrumentation.installed?
  end
end

.register_at_exit_flush!Object



74
75
76
77
78
79
80
81
82
83
# File 'lib/foam/ruby/otel_setup.rb', line 74

def register_at_exit_flush!
  at_exit do
    @foam_span_processor&.force_flush(timeout: 5)
    @foam_log_processor&.force_flush(timeout: 5)
    @foam_span_processor&.shutdown(timeout: 5)
    @foam_log_processor&.shutdown(timeout: 5)
  rescue Exception # rubocop:disable Lint/RescueException
    nil
  end
end

.require_instrumentations!Object



33
34
35
36
37
38
39
# File 'lib/foam/ruby/otel_setup.rb', line 33

def require_instrumentations!
  INSTRUMENTATIONS.each do |gem_name|
    require gem_name
  rescue LoadError
    nil
  end
end