diff --git a/packages/opentelemetry-node/src/propagator.ts b/packages/opentelemetry-node/src/propagator.ts index 4e0df90f912a..039dcc04a30d 100644 --- a/packages/opentelemetry-node/src/propagator.ts +++ b/packages/opentelemetry-node/src/propagator.ts @@ -1,17 +1,18 @@ import { + Baggage, Context, isSpanContextValid, + propagation, TextMapGetter, - TextMapPropagator, TextMapSetter, trace, TraceFlags, } from '@opentelemetry/api'; -import { isTracingSuppressed } from '@opentelemetry/core'; +import { isTracingSuppressed, W3CBaggagePropagator } from '@opentelemetry/core'; import { baggageHeaderToDynamicSamplingContext, - dynamicSamplingContextToSentryBaggageHeader, extractTraceparentData, + SENTRY_BAGGAGE_KEY_PREFIX, } from '@sentry/utils'; import { @@ -25,7 +26,7 @@ import { SENTRY_SPAN_PROCESSOR_MAP } from './spanprocessor'; /** * Injects and extracts `sentry-trace` and `baggage` headers from carriers. */ -export class SentryPropagator implements TextMapPropagator { +export class SentryPropagator extends W3CBaggagePropagator { /** * @inheritDoc */ @@ -41,10 +42,18 @@ export class SentryPropagator implements TextMapPropagator { if (span.transaction) { const dynamicSamplingContext = span.transaction.getDynamicSamplingContext(); - const sentryBaggageHeader = dynamicSamplingContextToSentryBaggageHeader(dynamicSamplingContext); - if (sentryBaggageHeader) { - setter.set(carrier, SENTRY_BAGGAGE_HEADER, sentryBaggageHeader); - } + + const baggage = propagation.getBaggage(context) || propagation.createBaggage({}); + const baggageWithSentryInfo = Object.entries(dynamicSamplingContext).reduce( + (b, [dscKey, dscValue]) => { + if (dscValue) { + return b.setEntry(`${SENTRY_BAGGAGE_KEY_PREFIX}${dscKey}`, { value: dscValue }); + } + return b; + }, + baggage, + ); + super.inject(propagation.setBaggage(context, baggageWithSentryInfo), carrier, setter); } } } diff --git a/packages/opentelemetry-node/test/propagator.test.ts b/packages/opentelemetry-node/test/propagator.test.ts index 49e2243fe8ee..ec7a047d7735 100644 --- a/packages/opentelemetry-node/test/propagator.test.ts +++ b/packages/opentelemetry-node/test/propagator.test.ts @@ -1,4 +1,11 @@ -import { defaultTextMapGetter, defaultTextMapSetter, ROOT_CONTEXT, trace, TraceFlags } from '@opentelemetry/api'; +import { + defaultTextMapGetter, + defaultTextMapSetter, + propagation, + ROOT_CONTEXT, + trace, + TraceFlags, +} from '@opentelemetry/api'; import { suppressTracing } from '@opentelemetry/core'; import { Hub, makeMain } from '@sentry/core'; import { addExtensionMethods, Transaction } from '@sentry/tracing'; @@ -138,6 +145,27 @@ describe('SentryPropagator', () => { expect(carrier[SENTRY_TRACE_HEADER]).toBe(sentryTrace); }); + it('should include existing baggage', () => { + const transactionContext = { + name: 'sampled-transaction', + traceId: 'd4cda95b652f4a1592b449d5929fda1b', + spanId: '6e0c63257de34c92', + sampled: true, + }; + const spanContext = { + traceId: 'd4cda95b652f4a1592b449d5929fda1b', + spanId: '6e0c63257de34c92', + traceFlags: TraceFlags.SAMPLED, + }; + createTransactionAndMaybeSpan(type, transactionContext); + const context = trace.setSpanContext(ROOT_CONTEXT, spanContext); + const baggage = propagation.createBaggage({ foo: { value: 'bar' } }); + propagator.inject(propagation.setBaggage(context, baggage), carrier, defaultTextMapSetter); + expect(carrier[SENTRY_BAGGAGE_HEADER]).toBe( + 'foo=bar,sentry-environment=production,sentry-release=1.0.0,sentry-transaction=sampled-transaction,sentry-public_key=abc,sentry-trace_id=d4cda95b652f4a1592b449d5929fda1b', + ); + }); + it('should NOT set baggage and sentry-trace header if instrumentation is supressed', () => { const spanContext = { traceId: 'd4cda95b652f4a1592b449d5929fda1b',