Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Send tracestate with w3c headers by default #550

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion packages/core/src/DdSdkReactNativeConfiguration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,10 @@ export const formatFirstPartyHosts = (
if (isLegacyFirstPartyHost(host)) {
return {
match: host,
propagatorTypes: [PropagatorType.DATADOG]
propagatorTypes: [
PropagatorType.DATADOG,
PropagatorType.TRACECONTEXT
]
};
}
return host;
Expand Down
20 changes: 16 additions & 4 deletions packages/core/src/__tests__/DdSdkReactNative.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -514,8 +514,14 @@ describe('DdSdkReactNative', () => {
'_dd.native_view_tracking': false,
'_dd.native_interaction_tracking': false,
'_dd.first_party_hosts': [
{ match: 'api.example.com', propagatorTypes: ['datadog'] },
{ match: 'something.fr', propagatorTypes: ['datadog'] }
{
match: 'api.example.com',
propagatorTypes: ['datadog', 'tracecontext']
},
{
match: 'something.fr',
propagatorTypes: ['datadog']
}
]
});
expect(DdRumResourceTracking.startTracking).toHaveBeenCalledTimes(
Expand All @@ -524,8 +530,14 @@ describe('DdSdkReactNative', () => {
expect(DdRumResourceTracking.startTracking).toHaveBeenCalledWith({
tracingSamplingRate: 42,
firstPartyHosts: [
{ match: 'api.example.com', propagatorTypes: ['datadog'] },
{ match: 'something.fr', propagatorTypes: ['datadog'] }
{
match: 'api.example.com',
propagatorTypes: ['datadog', 'tracecontext']
},
{
match: 'something.fr',
propagatorTypes: ['datadog']
}
]
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const PARENT_ID_HEADER_KEY = 'x-datadog-parent-id';
* OTel headers
*/
export const TRACECONTEXT_HEADER_KEY = 'traceparent';
export const TRACESTATE_HEADER_KEY = 'tracestate';
export const B3_HEADER_KEY = 'b3';
export const B3_MULTI_TRACE_ID_HEADER_KEY = 'X-B3-TraceId';
export const B3_MULTI_SPAN_ID_HEADER_KEY = 'X-B3-SpanId';
Expand Down Expand Up @@ -60,16 +61,26 @@ export const getTracingHeaders = (
break;
}
case PropagatorType.TRACECONTEXT: {
headers.push({
header: TRACECONTEXT_HEADER_KEY,
value: generateTraceContextHeader({
version: '00',
traceId: tracingAttributes.traceId,
parentId: tracingAttributes.spanId,
isSampled:
tracingAttributes.samplingPriorityHeader === '1'
})
});
headers.push(
{
header: TRACECONTEXT_HEADER_KEY,
value: generateTraceContextHeader({
version: '00',
traceId: tracingAttributes.traceId,
parentId: tracingAttributes.spanId,
isSampled:
tracingAttributes.samplingPriorityHeader === '1'
})
},
{
header: TRACESTATE_HEADER_KEY,
value: generateTraceStateHeader({
parentId: tracingAttributes.spanId,
isSampled:
tracingAttributes.samplingPriorityHeader === '1'
})
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like I have been asking everyone, can you make sure that data in the datadog headers is same as tracecontext headers?

A test on it would be much appreciated if these isn't one.

);
break;
}
case PropagatorType.B3: {
Expand Down Expand Up @@ -124,6 +135,20 @@ const generateTraceContextHeader = ({
)}-${parentId.toPaddedString(16, 16)}-${flags}`;
};

const generateTraceStateHeader = ({
parentId,
isSampled
}: {
parentId: SpanId;
isSampled: boolean;
}) => {
const sampled = `s:${isSampled ? '1' : '0'}`;
const origin = 'o:rum';
const parent = `p:${parentId.toPaddedString(16, 16)}`;

return `dd=${sampled};${origin};${parent}`;
};

const generateB3Header = ({
traceId,
spanId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import {
B3_MULTI_SPAN_ID_HEADER_KEY,
B3_MULTI_SAMPLED_HEADER_KEY,
ORIGIN_RUM,
ORIGIN_HEADER_KEY
ORIGIN_HEADER_KEY,
TRACESTATE_HEADER_KEY
} from '../../../distributedTracing/distributedTracingHeaders';
import { firstPartyHostsRegexMapBuilder } from '../../../distributedTracing/firstPartyHosts';
import {
Expand Down Expand Up @@ -54,6 +55,10 @@ const flushPromises = () =>
new Promise(jest.requireActual('timers').setImmediate);
let xhrProxy;

const hexToDecimal = (hex: string): string => {
return BigInt(`0x${hex}`).toString(10);
};

beforeEach(() => {
DdNativeRum.startResource.mockClear();
DdNativeRum.stopResource.mockClear();
Expand Down Expand Up @@ -444,8 +449,74 @@ describe('XHRProxy', () => {
await flushPromises();

// THEN
const headerValue = xhr.requestHeaders[TRACECONTEXT_HEADER_KEY];
expect(headerValue).toMatch(/^00-[0-9a-f]{32}-[0-9a-f]{16}-01$/);
const contextHeader = xhr.requestHeaders[TRACECONTEXT_HEADER_KEY];
expect(contextHeader).toMatch(/^00-[0-9a-f]{32}-[0-9a-f]{16}-01$/);

// Parent value of the context header is the 3rd part of it
const parentValue = contextHeader.split('-')[2];
const stateHeader = xhr.requestHeaders[TRACESTATE_HEADER_KEY];
expect(stateHeader).toBe(`dd=s:1;o:rum;p:${parentValue}`);
});

it('adds tracing headers with matching value when all headers are added', async () => {
// GIVEN
const method = 'GET';
const url = 'https://api.example.com:443/v2/user';
xhrProxy.onTrackingStart({
tracingSamplingRate: 100,
firstPartyHostsRegexMap: firstPartyHostsRegexMapBuilder([
{
match: 'example.com',
propagatorTypes: [PropagatorType.DATADOG]
},
{
match: 'example.com',
propagatorTypes: [PropagatorType.TRACECONTEXT]
},
{
match: 'example.com',
propagatorTypes: [PropagatorType.B3]
},
{
match: 'example.com',
propagatorTypes: [PropagatorType.B3MULTI]
}
])
});

// WHEN
const xhr = new XMLHttpRequestMock();
xhr.open(method, url);
xhr.send();
xhr.notifyResponseArrived();
xhr.complete(200, 'ok');
await flushPromises();

// THEN
const datadogTraceValue = xhr.requestHeaders[TRACE_ID_HEADER_KEY];
const datadogParentValue = xhr.requestHeaders[PARENT_ID_HEADER_KEY];

const contextHeader = xhr.requestHeaders[TRACECONTEXT_HEADER_KEY];
const traceContextValue = contextHeader.split('-')[1];
const parentContextValue = contextHeader.split('-')[2];

const b3MultiTraceHeader =
xhr.requestHeaders[B3_MULTI_TRACE_ID_HEADER_KEY];
const b3MultiParentHeader =
xhr.requestHeaders[B3_MULTI_SPAN_ID_HEADER_KEY];

const b3Header = xhr.requestHeaders[B3_HEADER_KEY];
const traceB3Value = b3Header.split('-')[0];
const parentB3Value = b3Header.split('-')[1];

expect(hexToDecimal(traceContextValue)).toBe(datadogTraceValue);
expect(hexToDecimal(parentContextValue)).toBe(datadogParentValue);

expect(hexToDecimal(b3MultiTraceHeader)).toBe(datadogTraceValue);
expect(hexToDecimal(b3MultiParentHeader)).toBe(datadogParentValue);

expect(hexToDecimal(traceB3Value)).toBe(datadogTraceValue);
expect(hexToDecimal(parentB3Value)).toBe(datadogParentValue);
});

it('adds tracecontext request headers when the host is instrumented with tracecontext and request is sampled', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,12 @@ describe('DatadogProvider', () => {
expect(
NativeModules.DdSdk.initialize.mock.calls[0][0]
.additionalConfig['_dd.first_party_hosts']
).toEqual([{ match: 'api.com', propagatorTypes: ['datadog'] }]);
).toEqual([
{
match: 'api.com',
propagatorTypes: ['datadog', 'tracecontext']
}
]);
expect(NativeModules.DdRum.addAction).toHaveBeenCalledTimes(1);
});
});
Expand Down