Skip to content

Commit 68a0f0f

Browse files
committed
fix(node): Ensure trace propagation works without spans in Node 23+
1 parent ba93128 commit 68a0f0f

File tree

4 files changed

+261
-84
lines changed

4 files changed

+261
-84
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,102 +1,204 @@
1-
import { describe,expect } from 'vitest';
1+
import { describe, expect } from 'vitest';
2+
import { conditionalTest } from '../../../../utils';
23
import { createEsmAndCjsTests } from '../../../../utils/runner';
34
import { createTestServer } from '../../../../utils/server';
45

5-
describe('outgoing http requests with tracing & spans disabled xxx', () => {
6+
describe('outgoing http requests with tracing & spans disabled', () => {
67
createEsmAndCjsTests(__dirname, 'scenario.mjs', 'instrument.mjs', (createRunner, test) => {
7-
test('outgoing http requests are correctly instrumented with tracing & spans disabled', async () => {
8-
expect.assertions(11);
8+
conditionalTest({ min: 23 })('node >=23', () => {
9+
test('outgoing http requests are correctly instrumented with tracing & spans disabled', async () => {
10+
expect.assertions(11);
911

10-
const [SERVER_URL, closeTestServer] = await createTestServer()
11-
.get('/api/v0', headers => {
12-
expect(headers['sentry-trace']).toEqual(expect.stringMatching(/^([a-f0-9]{32})-([a-f0-9]{16})$/));
13-
expect(headers['sentry-trace']).not.toEqual('00000000000000000000000000000000-0000000000000000');
14-
expect(headers['baggage']).toEqual(expect.any(String));
15-
})
16-
.get('/api/v1', headers => {
17-
expect(headers['sentry-trace']).toEqual(expect.stringMatching(/^([a-f0-9]{32})-([a-f0-9]{16})$/));
18-
expect(headers['sentry-trace']).not.toEqual('00000000000000000000000000000000-0000000000000000');
19-
expect(headers['baggage']).toEqual(expect.any(String));
20-
})
21-
.get('/api/v2', headers => {
22-
expect(headers['baggage']).toBeUndefined();
23-
expect(headers['sentry-trace']).toBeUndefined();
24-
})
25-
.get('/api/v3', headers => {
26-
expect(headers['baggage']).toBeUndefined();
27-
expect(headers['sentry-trace']).toBeUndefined();
28-
})
29-
.start();
12+
const [SERVER_URL, closeTestServer] = await createTestServer()
13+
.get('/api/v0', headers => {
14+
expect(headers['sentry-trace']).toEqual(expect.stringMatching(/^([a-f0-9]{32})-([a-f0-9]{16})$/));
15+
expect(headers['sentry-trace']).not.toEqual('00000000000000000000000000000000-0000000000000000');
16+
expect(headers['baggage']).toEqual(expect.any(String));
17+
})
18+
.get('/api/v1', headers => {
19+
expect(headers['sentry-trace']).toEqual(expect.stringMatching(/^([a-f0-9]{32})-([a-f0-9]{16})$/));
20+
expect(headers['sentry-trace']).not.toEqual('00000000000000000000000000000000-0000000000000000');
21+
expect(headers['baggage']).toEqual(expect.any(String));
22+
})
23+
.get('/api/v2', headers => {
24+
expect(headers['baggage']).toBeUndefined();
25+
expect(headers['sentry-trace']).toBeUndefined();
26+
})
27+
.get('/api/v3', headers => {
28+
expect(headers['baggage']).toBeUndefined();
29+
expect(headers['sentry-trace']).toBeUndefined();
30+
})
31+
.start();
3032

31-
await createRunner()
32-
.withEnv({ SERVER_URL })
33-
.ensureNoErrorOutput()
34-
.expect({
35-
event: {
36-
exception: {
37-
values: [
33+
await createRunner()
34+
.withEnv({ SERVER_URL })
35+
.ensureNoErrorOutput()
36+
.expect({
37+
event: {
38+
exception: {
39+
values: [
40+
{
41+
type: 'Error',
42+
value: 'foo',
43+
},
44+
],
45+
},
46+
breadcrumbs: [
47+
{
48+
message: 'manual breadcrumb',
49+
timestamp: expect.any(Number),
50+
},
51+
{
52+
category: 'http',
53+
data: {
54+
'http.method': 'GET',
55+
url: `${SERVER_URL}/api/v0`,
56+
status_code: 200,
57+
ADDED_PATH: '/api/v0',
58+
},
59+
timestamp: expect.any(Number),
60+
type: 'http',
61+
},
62+
{
63+
category: 'http',
64+
data: {
65+
'http.method': 'GET',
66+
url: `${SERVER_URL}/api/v1`,
67+
status_code: 200,
68+
ADDED_PATH: '/api/v1',
69+
},
70+
timestamp: expect.any(Number),
71+
type: 'http',
72+
},
3873
{
39-
type: 'Error',
40-
value: 'foo',
74+
category: 'http',
75+
data: {
76+
'http.method': 'GET',
77+
url: `${SERVER_URL}/api/v2`,
78+
status_code: 200,
79+
ADDED_PATH: '/api/v2',
80+
},
81+
timestamp: expect.any(Number),
82+
type: 'http',
83+
},
84+
{
85+
category: 'http',
86+
data: {
87+
'http.method': 'GET',
88+
url: `${SERVER_URL}/api/v3`,
89+
status_code: 200,
90+
ADDED_PATH: '/api/v3',
91+
},
92+
timestamp: expect.any(Number),
93+
type: 'http',
4194
},
4295
],
4396
},
44-
breadcrumbs: [
45-
{
46-
message: 'manual breadcrumb',
47-
timestamp: expect.any(Number),
97+
})
98+
.start()
99+
.completed();
100+
101+
closeTestServer();
102+
});
103+
});
104+
105+
// On older node versions, outgoing requests do not get trace-headers injected, sadly
106+
// This is because the necessary diagnostics channel hook is not available yet
107+
conditionalTest({ max: 22 })('node <=22', () => {
108+
test('outgoing http requests generate breadcrumbs correctly with tracing & spans disabled', async () => {
109+
expect.assertions(9);
110+
111+
const [SERVER_URL, closeTestServer] = await createTestServer()
112+
.get('/api/v0', headers => {
113+
// This is not instrumented, sadly
114+
expect(headers['baggage']).toBeUndefined();
115+
expect(headers['sentry-trace']).toBeUndefined();
116+
})
117+
.get('/api/v1', headers => {
118+
// This is not instrumented, sadly
119+
expect(headers['baggage']).toBeUndefined();
120+
expect(headers['sentry-trace']).toBeUndefined();
121+
})
122+
.get('/api/v2', headers => {
123+
expect(headers['baggage']).toBeUndefined();
124+
expect(headers['sentry-trace']).toBeUndefined();
125+
})
126+
.get('/api/v3', headers => {
127+
expect(headers['baggage']).toBeUndefined();
128+
expect(headers['sentry-trace']).toBeUndefined();
129+
})
130+
.start();
131+
132+
await createRunner()
133+
.withEnv({ SERVER_URL })
134+
.ensureNoErrorOutput()
135+
.expect({
136+
event: {
137+
exception: {
138+
values: [
139+
{
140+
type: 'Error',
141+
value: 'foo',
142+
},
143+
],
48144
},
49-
{
50-
category: 'http',
51-
data: {
52-
'http.method': 'GET',
53-
url: `${SERVER_URL}/api/v0`,
54-
status_code: 200,
55-
ADDED_PATH: '/api/v0',
145+
breadcrumbs: [
146+
{
147+
message: 'manual breadcrumb',
148+
timestamp: expect.any(Number),
56149
},
57-
timestamp: expect.any(Number),
58-
type: 'http',
59-
},
60-
{
61-
category: 'http',
62-
data: {
63-
'http.method': 'GET',
64-
url: `${SERVER_URL}/api/v1`,
65-
status_code: 200,
66-
ADDED_PATH: '/api/v1',
150+
{
151+
category: 'http',
152+
data: {
153+
'http.method': 'GET',
154+
url: `${SERVER_URL}/api/v0`,
155+
status_code: 200,
156+
ADDED_PATH: '/api/v0',
157+
},
158+
timestamp: expect.any(Number),
159+
type: 'http',
67160
},
68-
timestamp: expect.any(Number),
69-
type: 'http',
70-
},
71-
{
72-
category: 'http',
73-
data: {
74-
'http.method': 'GET',
75-
url: `${SERVER_URL}/api/v2`,
76-
status_code: 200,
77-
ADDED_PATH: '/api/v2',
161+
{
162+
category: 'http',
163+
data: {
164+
'http.method': 'GET',
165+
url: `${SERVER_URL}/api/v1`,
166+
status_code: 200,
167+
ADDED_PATH: '/api/v1',
168+
},
169+
timestamp: expect.any(Number),
170+
type: 'http',
78171
},
79-
timestamp: expect.any(Number),
80-
type: 'http',
81-
},
82-
{
83-
category: 'http',
84-
data: {
85-
'http.method': 'GET',
86-
url: `${SERVER_URL}/api/v3`,
87-
status_code: 200,
88-
ADDED_PATH: '/api/v3',
172+
{
173+
category: 'http',
174+
data: {
175+
'http.method': 'GET',
176+
url: `${SERVER_URL}/api/v2`,
177+
status_code: 200,
178+
ADDED_PATH: '/api/v2',
179+
},
180+
timestamp: expect.any(Number),
181+
type: 'http',
89182
},
90-
timestamp: expect.any(Number),
91-
type: 'http',
92-
},
93-
],
94-
},
95-
})
96-
.start()
97-
.completed();
183+
{
184+
category: 'http',
185+
data: {
186+
'http.method': 'GET',
187+
url: `${SERVER_URL}/api/v3`,
188+
status_code: 200,
189+
ADDED_PATH: '/api/v3',
190+
},
191+
timestamp: expect.any(Number),
192+
type: 'http',
193+
},
194+
],
195+
},
196+
})
197+
.start()
198+
.completed();
98199

99-
closeTestServer();
200+
closeTestServer();
201+
});
100202
});
101203
});
102204
});

dev-packages/node-integration-tests/suites/vercel/test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { afterAll, describe, expect } from 'vitest';
22
import { cleanupChildProcesses, createEsmAndCjsTests } from '../../utils/runner';
33

4-
describe('vercel xxx', () => {
4+
describe('vercel', () => {
55
afterAll(() => {
66
cleanupChildProcesses();
77
});

0 commit comments

Comments
 (0)