From 9fe7fe4f9b2555f39bb25e0c6f908e54c1108c2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A1vio=20Lucena?= Date: Sun, 24 Aug 2025 20:50:44 -0700 Subject: [PATCH 1/2] feat: include otel as custom sampling contex Sentry's opentelemetry adapter does not do the greatest job in adapting the opentelemetry span to a semantically correct sentry span, nor does it expose the opentelemetry span in the context for sampling decisions. This PR adds a opentelemetry span as an additional custom sampling context so it can be used for sampling decisions. This gives clients more opportunity to use the entire context of the opentelemetry span for sampling decisions, and allows replicating sampling mechanisms as orignally suggested by the Sentry team via the "Sampling Function". https://docs.sentry.io/platforms/ruby/configuration/sampling/#setting-a-sampling-function --- .../lib/sentry/opentelemetry/span_processor.rb | 11 ++++++++++- .../sentry/opentelemetry/span_processor_spec.rb | 14 ++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/sentry-opentelemetry/lib/sentry/opentelemetry/span_processor.rb b/sentry-opentelemetry/lib/sentry/opentelemetry/span_processor.rb index e898c6b33..79efdcbda 100644 --- a/sentry-opentelemetry/lib/sentry/opentelemetry/span_processor.rb +++ b/sentry-opentelemetry/lib/sentry/opentelemetry/span_processor.rb @@ -48,7 +48,16 @@ def on_start(otel_span, parent_context) parent_sampled: trace_data.parent_sampled, baggage: trace_data.baggage, start_timestamp: otel_span.start_timestamp / 1e9, - origin: SPAN_ORIGIN + origin: SPAN_ORIGIN, + custom_sampling_context: { + otel: otel_context_hash(otel_span).merge( + kind: otel_span.kind, + instrumentation_scope: { + name: otel_span.instrumentation_scope.name, + version: otel_span.instrumentation_scope.version + } + ) + } } Sentry.start_transaction(**options) diff --git a/sentry-opentelemetry/spec/sentry/opentelemetry/span_processor_spec.rb b/sentry-opentelemetry/spec/sentry/opentelemetry/span_processor_spec.rb index 194af2c52..ba8610d17 100644 --- a/sentry-opentelemetry/spec/sentry/opentelemetry/span_processor_spec.rb +++ b/sentry-opentelemetry/spec/sentry/opentelemetry/span_processor_spec.rb @@ -154,6 +154,20 @@ it 'starts a sentry transaction on otel root span' do expect(Sentry).to receive(:start_transaction).and_call_original + expect_any_instance_of(Sentry::Transaction).to receive(:set_initial_sample_decision).with( + sampling_context: a_hash_including( + otel: { + attributes: root_span.attributes, + resource: root_span.resource.attribute_enumerator.to_h, + kind: root_span.kind, + instrumentation_scope: { + name: root_span.instrumentation_scope.name, + version: root_span.instrumentation_scope.version + } + } + ) + ) + subject.on_start(root_span, empty_context) span_id = root_span.context.hex_span_id From 7c8ab68175b91edaab8db9ddeab5293445f6c367 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A1vio=20Lucena?= Date: Wed, 24 Sep 2025 21:10:03 -0700 Subject: [PATCH 2/2] chore: exercise otel context with tracer_sampler --- .../opentelemetry/span_processor_spec.rb | 39 ++++++++++++------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/sentry-opentelemetry/spec/sentry/opentelemetry/span_processor_spec.rb b/sentry-opentelemetry/spec/sentry/opentelemetry/span_processor_spec.rb index ba8610d17..b5dcb8b7a 100644 --- a/sentry-opentelemetry/spec/sentry/opentelemetry/span_processor_spec.rb +++ b/sentry-opentelemetry/spec/sentry/opentelemetry/span_processor_spec.rb @@ -154,19 +154,6 @@ it 'starts a sentry transaction on otel root span' do expect(Sentry).to receive(:start_transaction).and_call_original - expect_any_instance_of(Sentry::Transaction).to receive(:set_initial_sample_decision).with( - sampling_context: a_hash_including( - otel: { - attributes: root_span.attributes, - resource: root_span.resource.attribute_enumerator.to_h, - kind: root_span.kind, - instrumentation_scope: { - name: root_span.instrumentation_scope.name, - version: root_span.instrumentation_scope.version - } - } - ) - ) subject.on_start(root_span, empty_context) @@ -189,6 +176,32 @@ expect(transaction.baggage).to eq(nil) end + it 'includes otel context in custom sampling context' do + sampling_context = nil + Sentry.configuration.traces_sampler = lambda do |context| + sampling_context = context + 0.5 + end + + subject.on_start(root_span, empty_context) + + expect(sampling_context).to include(:otel) + otel_context = sampling_context[:otel] + + expect(otel_context).to include( + kind: root_span.kind, + instrumentation_scope: { + name: root_span.instrumentation_scope.name, + version: root_span.instrumentation_scope.version + } + ) + + expect(otel_context).to include(attributes: root_span.attributes) + + resource_attributes = root_span.resource.attribute_enumerator.to_h + expect(otel_context).to include(resource: resource_attributes) + end + context 'with started transaction' do let(:transaction) do subject.on_start(root_span, empty_context)