Skip to content

Commit 5ea3e06

Browse files
sl0thentr0pyclaude
andcommitted
feat(otlp): Add collector_url option to OTLP integration
Allow users with their own OpenTelemetry collector to pass a custom collector URL via config.otlp.collector_url. When set, traces are sent to the specified endpoint without Sentry auth headers. When not set, the existing behavior of deriving the endpoint from the DSN is preserved. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 8205acb commit 5ea3e06

5 files changed

Lines changed: 89 additions & 11 deletions

File tree

sentry-opentelemetry/Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ eval_gemfile "../Gemfile.dev"
99
gemspec
1010

1111
gem "opentelemetry-sdk"
12+
gem "opentelemetry-exporter-otlp"
1213
gem "opentelemetry-instrumentation-rails"
1314

1415
gem "sentry-ruby", path: "../sentry-ruby"

sentry-opentelemetry/lib/sentry/opentelemetry/configuration.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,13 @@ module OTLP
2121
class Configuration
2222
attr_accessor :enabled
2323
attr_accessor :setup_otlp_traces_exporter
24+
attr_accessor :collector_url
2425
attr_accessor :setup_propagator
2526

2627
def initialize
2728
@enabled = false
2829
@setup_otlp_traces_exporter = true
30+
@collector_url = nil
2931
@setup_propagator = true
3032
end
3133
end

sentry-opentelemetry/lib/sentry/opentelemetry/otlp_setup.rb

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ module OTLPSetup
1111
class << self
1212
def setup(config)
1313
@dsn = config.dsn
14+
@collector_url = config.otlp.collector_url
1415
@sdk_logger = config.sdk_logger
1516
log_debug("[OTLP] Setting up OTLP integration")
1617

@@ -39,7 +40,7 @@ def setup_external_propagation_context
3940
end
4041

4142
def setup_otlp_exporter
42-
return unless @dsn
43+
return unless @dsn || @collector_url
4344

4445
log_debug("[OTLP] Setting up OTLP exporter")
4546

@@ -51,15 +52,20 @@ def setup_otlp_exporter
5152
return
5253
end
5354

54-
endpoint = "#{@dsn.server}#{@dsn.otlp_traces_endpoint}"
55-
auth_header = @dsn.generate_auth_header(client: USER_AGENT)
55+
exporter = if @collector_url
56+
endpoint = @collector_url
57+
headers = {}
58+
log_debug("[OTLP] Sending traces to collector at #{endpoint}")
5659

57-
log_debug("[OTLP] Sending traces to #{endpoint}")
60+
::OpenTelemetry::Exporter::OTLP::Exporter.new(endpoint: endpoint)
61+
else
62+
endpoint = "#{@dsn.server}#{@dsn.otlp_traces_endpoint}"
63+
auth_header = @dsn.generate_auth_header(client: USER_AGENT)
64+
headers = { "X-Sentry-Auth" => auth_header }
65+
log_debug("[OTLP] Sending traces to #{endpoint}")
5866

59-
exporter = ::OpenTelemetry::Exporter::OTLP::Exporter.new(
60-
endpoint: endpoint,
61-
headers: { "X-Sentry-Auth" => auth_header }
62-
)
67+
::OpenTelemetry::Exporter::OTLP::Exporter.new(endpoint: endpoint, headers: headers)
68+
end
6369

6470
span_processor = ::OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(exporter)
6571
::OpenTelemetry.tracer_provider.add_span_processor(span_processor)

sentry-opentelemetry/spec/sentry/opentelemetry/configuration_spec.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
it "sets default values" do
88
expect(subject.enabled).to eq(false)
99
expect(subject.setup_otlp_traces_exporter).to eq(true)
10+
expect(subject.collector_url).to be_nil
1011
expect(subject.setup_propagator).to eq(true)
1112
end
1213
end
@@ -17,6 +18,11 @@
1718
expect(subject.enabled).to eq(true)
1819
end
1920

21+
it "allows setting collector_url" do
22+
subject.collector_url = "http://localhost:4318/v1/traces"
23+
expect(subject.collector_url).to eq("http://localhost:4318/v1/traces")
24+
end
25+
2026
it "allows setting setup_otlp_traces_exporter" do
2127
subject.setup_otlp_traces_exporter = false
2228
expect(subject.setup_otlp_traces_exporter).to eq(false)

sentry-opentelemetry/spec/sentry/opentelemetry/otlp_setup_spec.rb

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
perform_otel_setup
88
end
99

10+
def span_processors
11+
::OpenTelemetry.tracer_provider.instance_variable_get(:@span_processors)
12+
end
13+
1014
describe '.setup' do
1115
context 'with setup_propagator enabled' do
1216
before do
@@ -24,20 +28,79 @@
2428
end
2529

2630
context 'with setup_otlp_traces_exporter enabled' do
27-
before do
28-
perform_basic_setup do |config|
29-
config.otlp.enabled = true
31+
context 'without collector_url (default DSN-based endpoint)' do
32+
before do
33+
perform_basic_setup do |config|
34+
config.otlp.enabled = true
35+
config.otlp.setup_otlp_traces_exporter = true
36+
end
37+
end
38+
39+
it 'creates the exporter with the DSN endpoint and auth headers' do
40+
dsn = Sentry.configuration.dsn
41+
expected_endpoint = "#{dsn.server}#{dsn.otlp_traces_endpoint}"
42+
43+
expect(::OpenTelemetry::Exporter::OTLP::Exporter).to receive(:new)
44+
.with(endpoint: expected_endpoint, headers: hash_including("X-Sentry-Auth"))
45+
.and_call_original
46+
47+
described_class.setup(Sentry.configuration)
48+
49+
expect(span_processors.last).to be_a(::OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor)
50+
end
51+
end
52+
53+
context 'with collector_url' do
54+
let(:collector_url) { "http://localhost:4318/v1/traces" }
55+
56+
before do
57+
perform_basic_setup do |config|
58+
config.otlp.enabled = true
59+
config.otlp.setup_otlp_traces_exporter = true
60+
config.otlp.collector_url = collector_url
61+
end
62+
end
63+
64+
it 'creates the exporter with the collector endpoint' do
65+
expect(::OpenTelemetry::Exporter::OTLP::Exporter).to receive(:new)
66+
.with(endpoint: collector_url)
67+
.and_call_original
68+
69+
described_class.setup(Sentry.configuration)
70+
71+
expect(span_processors.last).to be_a(::OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor)
3072
end
3173
end
3274

3375
it 'logs a warning when opentelemetry-exporter-otlp is not installed' do
76+
perform_basic_setup do |config|
77+
config.otlp.enabled = true
78+
config.otlp.setup_otlp_traces_exporter = true
79+
end
80+
3481
allow_any_instance_of(Object).to receive(:require).with("opentelemetry/exporter/otlp").and_raise(LoadError)
3582

3683
expect(Sentry.configuration.sdk_logger).to receive(:warn).with(/opentelemetry-exporter-otlp gem is not installed/)
3784
described_class.setup(Sentry.configuration)
3885
end
3986
end
4087

88+
context 'with setup_otlp_traces_exporter disabled' do
89+
before do
90+
perform_basic_setup do |config|
91+
config.otlp.enabled = true
92+
config.otlp.setup_otlp_traces_exporter = false
93+
end
94+
end
95+
96+
it 'does not add a span processor' do
97+
processors_before = span_processors.length
98+
described_class.setup(Sentry.configuration)
99+
100+
expect(span_processors.length).to eq(processors_before)
101+
end
102+
end
103+
41104
context 'with external propagation context' do
42105
before do
43106
perform_basic_setup do |config|

0 commit comments

Comments
 (0)