Skip to content

Commit ea2d920

Browse files
committed
feat(cloudflare): Support propagateTraceparent
1 parent 12f3007 commit ea2d920

File tree

17 files changed

+148
-102
lines changed

17 files changed

+148
-102
lines changed

dev-packages/cloudflare-integration-tests/runner.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,13 @@ export function createRunner(...paths: string[]) {
6464
const expectedEnvelopes: Expected[] = [];
6565
// By default, we ignore session & sessions
6666
const ignored: Set<EnvelopeItemType> = new Set(['session', 'sessions', 'client_report']);
67+
let serverUrl: string | undefined;
6768

6869
return {
70+
withServerUrl: function (url: string) {
71+
serverUrl = url;
72+
return this;
73+
},
6974
expect: function (expected: Expected) {
7075
expectedEnvelopes.push(expected);
7176
return this;
@@ -154,6 +159,8 @@ export function createRunner(...paths: string[]) {
154159
'false',
155160
'--var',
156161
`SENTRY_DSN:http://public@localhost:${mockServerPort}/1337`,
162+
'--var',
163+
`SERVER_URL:${serverUrl}`,
157164
],
158165
{ stdio, signal },
159166
);
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import * as Sentry from '@sentry/cloudflare';
2+
3+
interface Env {
4+
SENTRY_DSN: string;
5+
SERVER_URL: string;
6+
}
7+
8+
export default Sentry.withSentry(
9+
(env: Env) => ({
10+
dsn: env.SENTRY_DSN,
11+
propagateTraceparent: true,
12+
}),
13+
{
14+
async fetch(_request, env, _ctx) {
15+
await fetch(env.SERVER_URL);
16+
throw new Error('Test error to capture trace headers');
17+
},
18+
},
19+
);
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { createTestServer } from '@sentry-internal/test-utils';
2+
import { expect, it } from 'vitest';
3+
import { eventEnvelope } from '../../../expect';
4+
import { createRunner } from '../../../runner';
5+
6+
it('Tracing headers', async ({ signal }) => {
7+
expect.assertions(5);
8+
9+
const [SERVER_URL, closeTestServer] = await createTestServer()
10+
.get('/', headers => {
11+
expect(headers['baggage']).toEqual(expect.any(String));
12+
expect(headers['sentry-trace']).toEqual(expect.stringMatching(/^([a-f\d]{32})-([a-f\d]{16})-0$/));
13+
expect(headers['sentry-trace']).not.toEqual('00000000000000000000000000000000-0000000000000000-0');
14+
expect(headers['traceparent']).toEqual(expect.stringMatching(/^00-([a-f\d]{32})-([a-f\d]{16})-00$/));
15+
})
16+
.start();
17+
18+
const runner = createRunner(__dirname)
19+
.withServerUrl(SERVER_URL)
20+
.expect(
21+
eventEnvelope({
22+
level: 'error',
23+
exception: {
24+
values: [
25+
{
26+
type: 'Error',
27+
value: 'Test error to capture trace headers',
28+
stacktrace: {
29+
frames: expect.any(Array),
30+
},
31+
mechanism: { type: 'auto.http.cloudflare', handled: false },
32+
},
33+
],
34+
},
35+
breadcrumbs: [
36+
{
37+
category: 'fetch',
38+
data: {
39+
method: 'GET',
40+
status_code: 200,
41+
url: expect.stringContaining('http://localhost:'),
42+
},
43+
timestamp: expect.any(Number),
44+
type: 'http',
45+
},
46+
],
47+
request: {
48+
headers: expect.any(Object),
49+
method: 'GET',
50+
url: expect.any(String),
51+
},
52+
}),
53+
)
54+
.start(signal);
55+
56+
await runner.makeRequest('get', '/');
57+
await runner.completed();
58+
closeTestServer();
59+
});
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"name": "worker-name",
3+
"compatibility_date": "2025-06-17",
4+
"main": "index.ts",
5+
"compatibility_flags": ["nodejs_compat"]
6+
}

dev-packages/node-core-integration-tests/suites/tracing/dsc-txn-name-update/test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1+
import { createTestServer } from '@sentry-internal/test-utils';
12
import { expect, test } from 'vitest';
23
import { conditionalTest } from '../../../utils';
34
import { createRunner } from '../../../utils/runner';
4-
import { createTestServer } from '../../../utils/server';
55

66
// This test requires Node.js 22+ because it depends on the 'http.client.request.created'
77
// diagnostic channel for baggage header propagation, which only exists since Node 22.12.0+ and 23.2.0+

dev-packages/node-core-integration-tests/suites/tracing/requests/traceparent/test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
import { createTestServer } from '@sentry-internal/test-utils';
12
import { describe, expect } from 'vitest';
23
import { createEsmAndCjsTests } from '../../../../utils/runner';
3-
import { createTestServer } from '../../../../utils/server';
44

55
describe('outgoing traceparent', () => {
66
createEsmAndCjsTests(__dirname, 'scenario-fetch.mjs', 'instrument.mjs', (createRunner, test) => {

dev-packages/node-core-integration-tests/suites/tracing/tracePropagationTargets/test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1+
import { createTestServer } from '@sentry-internal/test-utils';
12
import { expect, test } from 'vitest';
23
import { conditionalTest } from '../../../utils';
34
import { createRunner } from '../../../utils/runner';
4-
import { createTestServer } from '../../../utils/server';
55

66
// This test requires Node.js 22+ because it depends on the 'http.client.request.created'
77
// diagnostic channel for baggage header propagation, which only exists since Node 22.12.0+ and 23.2.0+

dev-packages/node-core-integration-tests/utils/server.ts

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -38,48 +38,3 @@ export function createBasicSentryServer(onEnvelope: (env: Envelope) => void): Pr
3838
});
3939
}
4040

41-
type HeaderAssertCallback = (headers: Record<string, string | string[] | undefined>) => void;
42-
43-
/** Creates a test server that can be used to check headers */
44-
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
45-
export function createTestServer() {
46-
const gets: Array<[string, HeaderAssertCallback, number]> = [];
47-
let error: unknown | undefined;
48-
49-
return {
50-
get: function (path: string, callback: HeaderAssertCallback, result = 200) {
51-
gets.push([path, callback, result]);
52-
return this;
53-
},
54-
start: async (): Promise<[string, () => void]> => {
55-
const app = express();
56-
57-
for (const [path, callback, result] of gets) {
58-
app.get(path, (req, res) => {
59-
try {
60-
callback(req.headers);
61-
} catch (e) {
62-
error = e;
63-
}
64-
65-
res.status(result).send();
66-
});
67-
}
68-
69-
return new Promise(resolve => {
70-
const server = app.listen(0, () => {
71-
const address = server.address() as AddressInfo;
72-
resolve([
73-
`http://localhost:${address.port}`,
74-
() => {
75-
server.close();
76-
if (error) {
77-
throw error;
78-
}
79-
},
80-
]);
81-
});
82-
});
83-
},
84-
};
85-
}

dev-packages/node-integration-tests/suites/tracing/dsc-txn-name-update/test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
import { createTestServer } from '@sentry-internal/test-utils';
12
import { expect, test } from 'vitest';
23
import { createRunner } from '../../../utils/runner';
3-
import { createTestServer } from '../../../utils/server';
44

55
test('adds current transaction name to baggage when the txn name is high-quality', async () => {
66
expect.assertions(5);

dev-packages/node-integration-tests/suites/tracing/http-client-spans/fetch-basic/test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
import { createTestServer } from '@sentry-internal/test-utils';
12
import { expect, test } from 'vitest';
23
import { createRunner } from '../../../../utils/runner';
3-
import { createTestServer } from '../../../../utils/server';
44

55
test('captures spans for outgoing fetch requests', async () => {
66
expect.assertions(3);

0 commit comments

Comments
 (0)