diff --git a/packages/core/src/rum/instrumentation/resourceTracking/distributedTracing/distributedTracing.tsx b/packages/core/src/rum/instrumentation/resourceTracking/distributedTracing/distributedTracing.tsx index e529f3cd1..c8d54d32a 100644 --- a/packages/core/src/rum/instrumentation/resourceTracking/distributedTracing/distributedTracing.tsx +++ b/packages/core/src/rum/instrumentation/resourceTracking/distributedTracing/distributedTracing.tsx @@ -26,12 +26,14 @@ export type DdRumResourceTracingAttributes = rulePsr: number; propagatorTypes: PropagatorType[]; rumSessionId?: string; + baggageHeaders?: Set; } | { tracingStrategy: 'DISCARD'; traceId?: void; spanId?: void; samplingPriorityHeader: '0'; + baggageHeaders?: Set; }; const DISCARDED_TRACE_ATTRIBUTES: DdRumResourceTracingAttributes = { diff --git a/packages/core/src/rum/instrumentation/resourceTracking/distributedTracing/distributedTracingHeaders.ts b/packages/core/src/rum/instrumentation/resourceTracking/distributedTracing/distributedTracingHeaders.ts index f4decf2ac..3559c30d1 100644 --- a/packages/core/src/rum/instrumentation/resourceTracking/distributedTracing/distributedTracingHeaders.ts +++ b/packages/core/src/rum/instrumentation/resourceTracking/distributedTracing/distributedTracingHeaders.ts @@ -138,9 +138,22 @@ export const getTracingHeadersFromAttributes = ( } } if (tracingAttributes.rumSessionId) { + if (!tracingAttributes.baggageHeaders) { + tracingAttributes.baggageHeaders = new Set(); + } + + tracingAttributes.baggageHeaders?.add( + `${DD_RUM_SESSION_ID_TAG}=${tracingAttributes.rumSessionId}` + ); + } + + const baggageHeader = tracingAttributes.baggageHeaders + ? Array.from(tracingAttributes.baggageHeaders).join(', ') + : null; + if (baggageHeader) { headers.push({ header: BAGGAGE_HEADER_KEY, - value: `${DD_RUM_SESSION_ID_TAG}=${tracingAttributes.rumSessionId}` + value: baggageHeader }); } }); diff --git a/packages/core/src/rum/instrumentation/resourceTracking/requestProxy/XHRProxy/XHRProxy.ts b/packages/core/src/rum/instrumentation/resourceTracking/requestProxy/XHRProxy/XHRProxy.ts index e81c8014f..11966d39a 100644 --- a/packages/core/src/rum/instrumentation/resourceTracking/requestProxy/XHRProxy/XHRProxy.ts +++ b/packages/core/src/rum/instrumentation/resourceTracking/requestProxy/XHRProxy/XHRProxy.ts @@ -6,7 +6,10 @@ import { Timer } from '../../../../../utils/Timer'; import { getCachedSessionId } from '../../../../sessionId/sessionIdHelper'; -import { getTracingHeadersFromAttributes } from '../../distributedTracing/distributedTracingHeaders'; +import { + BAGGAGE_HEADER_KEY, + getTracingHeadersFromAttributes +} from '../../distributedTracing/distributedTracingHeaders'; import type { DdRumResourceTracingAttributes } from '../../distributedTracing/distributedTracing'; import { getTracingAttributes } from '../../distributedTracing/distributedTracing'; import { @@ -226,6 +229,14 @@ const proxySetRequestHeader = (providers: XHRProxyProviders): void => { } } + if (header.toLowerCase() === BAGGAGE_HEADER_KEY) { + if (!this._datadog_xhr.tracingAttributes.baggageHeaders) { + this._datadog_xhr.tracingAttributes.baggageHeaders = new Set(); + } + + this._datadog_xhr.tracingAttributes.baggageHeaders?.add(value); + } + // eslint-disable-next-line prefer-rest-params return originalXhrSetRequestHeader.apply(this, arguments as any); }; diff --git a/packages/core/src/rum/instrumentation/resourceTracking/requestProxy/XHRProxy/__tests__/XHRProxy.test.ts b/packages/core/src/rum/instrumentation/resourceTracking/requestProxy/XHRProxy/__tests__/XHRProxy.test.ts index 907bfe57a..c6fb8c4fb 100644 --- a/packages/core/src/rum/instrumentation/resourceTracking/requestProxy/XHRProxy/__tests__/XHRProxy.test.ts +++ b/packages/core/src/rum/instrumentation/resourceTracking/requestProxy/XHRProxy/__tests__/XHRProxy.test.ts @@ -839,6 +839,55 @@ describe('XHRProxy', () => { // THEN expect(xhr.requestHeaders[BAGGAGE_HEADER_KEY]).toBeUndefined(); }); + + it('rum session id does not overwrite existing baggage headers', async () => { + // GIVEN + const method = 'GET'; + const url = 'https://api.example.com:443/v2/user'; + xhrProxy.onTrackingStart({ + tracingSamplingRate: 100, + firstPartyHostsRegexMap: firstPartyHostsRegexMapBuilder([ + { + match: 'api.example.com', + propagatorTypes: [ + PropagatorType.DATADOG, + PropagatorType.TRACECONTEXT + ] + }, + { + match: 'example.com', + propagatorTypes: [ + PropagatorType.B3, + PropagatorType.B3MULTI + ] + } + ]) + }); + + setCachedSessionId('TEST-SESSION-ID'); + + // WHEN + const xhr = new XMLHttpRequestMock(); + xhr.open(method, url); + xhr.setRequestHeader('baggage', 'existing.key=existing-value'); + xhr.send(); + xhr.notifyResponseArrived(); + xhr.complete(200, 'ok'); + await flushPromises(); + + // THEN + expect(xhr.requestHeaders[BAGGAGE_HEADER_KEY]).not.toBeUndefined(); + expect(xhr.requestHeaders[BAGGAGE_HEADER_KEY]).toContain( + 'existing.key=existing-value' + ); + + const values = xhr.requestHeaders[BAGGAGE_HEADER_KEY].split( + ', ' + ).sort(); + + expect(values[0]).toBe('existing.key=existing-value'); + expect(values[1]).toBe('session.id=TEST-SESSION-ID'); + }); }); describe('DdRum.startResource calls', () => {