Skip to content
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import * as Sentry from '@sentry/browser';

window.Sentry = Sentry;

Sentry.init({
dsn: 'https://public@dsn.ingest.sentry.io/1337',
integrations: [Sentry.browserTracingIntegration()],
tracePropagationTargets: ['sentry-test-external.io'],
tracesSampleRate: 1,
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Sentry.startSpan({ name: 'standalone_span', experimental: { standalone: true } }, () => {
fetch('http://sentry-test-external.io');
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="sentry-trace" content="12345678901234567890123456789012-1234567890123456-1" />
<!-- baggage meta tag omitted on purpose -->
</head>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { expect } from '@playwright/test';
import type { SpanEnvelope } from '@sentry/core';
import { sentryTest } from '../../../../utils/fixtures';
import {
getMultipleSentryEnvelopeRequests,
properFullEnvelopeRequestParser,
shouldSkipTracingTest,
} from '../../../../utils/helpers';

const TRACE_ID = '12345678901234567890123456789012';
const OUTGOING_REQUEST_URL = 'http://sentry-test-external.io';

sentryTest(
'omits the trace envelope header when a standalone span continues a trace without baggage',
async ({ getLocalTestUrl, page }) => {
sentryTest.skip(shouldSkipTracingTest());

const url = await getLocalTestUrl({ testDir: __dirname });
await page.route(OUTGOING_REQUEST_URL, route => route.fulfill({ status: 200, body: 'ok' }));
const outgoingRequestPromise = page.waitForRequest(OUTGOING_REQUEST_URL);

const [spanEnvelope] = await getMultipleSentryEnvelopeRequests<SpanEnvelope>(
page,
1,
{ url, envelopeType: 'span' },
properFullEnvelopeRequestParser,
);
const outgoingRequest = await outgoingRequestPromise;

expect(spanEnvelope[0]).toEqual({
sent_at: expect.any(String),
});

// To be clear: This is _expected_ behavior, not a bug.
// SDKs must assume that an incoming `sentry-trace` but no `baggage` meta tag means that the
// trace was started from an SDK that's not yet compatible with the DSC or baggage propagation.
// The test demonstrates that the SDK as expected continues the trace but does not send a `trace`
// header, nor a baggage header.
expect(spanEnvelope[0].trace).toBeUndefined();

expect(spanEnvelope[1]).toHaveLength(1);
expect(spanEnvelope[1][0][1].trace_id).toBe(TRACE_ID);

const outgoingRequestHeaders = outgoingRequest.headers();
expect(outgoingRequestHeaders['sentry-trace']).toMatch(new RegExp(`^${TRACE_ID}-[\\da-f]{16}-1$`));
expect(outgoingRequestHeaders['baggage']).toBeUndefined();
},
);
10 changes: 7 additions & 3 deletions packages/core/src/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,11 @@ export function _INTERNAL_getTracingHeadersForFetchRequest(
const originalHeaders = fetchOptionsObj.headers || (isRequest(request) ? request.headers : undefined);

if (!originalHeaders) {
return { ...traceHeaders };
return {
'sentry-trace': sentryTrace,
...(baggage && { baggage }),
...(traceparent && { traceparent }),
};
Comment thread
cursor[bot] marked this conversation as resolved.
} else if (isHeaders(originalHeaders)) {
const newHeaders = new Headers(originalHeaders);

Expand Down Expand Up @@ -292,11 +296,11 @@ export function _INTERNAL_getTracingHeadersForFetchRequest(

const newHeaders: {
'sentry-trace': string;
baggage: string | undefined;
baggage?: string;
traceparent?: string;
} = Object.assign({}, originalHeaders, {
'sentry-trace': (existingSentryTraceHeader as string | undefined) ?? sentryTrace,
baggage: newBaggageHeaders.length > 0 ? newBaggageHeaders.join(',') : undefined,
...(newBaggageHeaders.length > 0 && { baggage: newBaggageHeaders.join(',') }),
});

if (propagateTraceparent && traceparent && !existingTraceparentHeader) {
Expand Down
15 changes: 15 additions & 0 deletions packages/core/test/lib/fetch.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,21 @@ describe('_INTERNAL_getTracingHeadersForFetchRequest', () => {
});
});

it('omits baggage from headers object when no baggage is available', () => {
vi.mocked(traceData.getTraceData).mockReturnValueOnce({
'sentry-trace': DEFAULT_SENTRY_TRACE,
});

const returnedHeaders = _INTERNAL_getTracingHeadersForFetchRequest('/api/test', {
headers: { 'custom-header': 'custom-value' },
});

expect(returnedHeaders).toStrictEqual({
'sentry-trace': DEFAULT_SENTRY_TRACE,
'custom-header': 'custom-value',
});
});

it('attaches sentry headers to a Headers instance', () => {
const returnedHeaders = _INTERNAL_getTracingHeadersForFetchRequest('/api/test', {
headers: new Headers({ 'custom-header': 'custom-value' }),
Expand Down
Loading