Skip to content

Commit 56f0d7a

Browse files
authored
test(node): Add tests for full http.server span attribute coverage (#17373)
Add tests that definitely show: 1. How get and post spans are captured 2. How URLs are handled with params and fragments This should make #17371 much easier to verify.
1 parent 508afcc commit 56f0d7a

File tree

6 files changed

+173
-109
lines changed

6 files changed

+173
-109
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import * as Sentry from '@sentry/node';
2+
import { loggingTransport } from '@sentry-internal/node-integration-tests';
3+
4+
Sentry.init({
5+
dsn: 'https://[email protected]/1337',
6+
release: '1.0',
7+
// disable attaching headers to /test/* endpoints
8+
tracePropagationTargets: [/^(?!.*test).*$/],
9+
tracesSampleRate: 1.0,
10+
transport: loggingTransport,
11+
12+
integrations: [
13+
Sentry.httpIntegration({
14+
instrumentation: {
15+
requestHook: (span, req) => {
16+
span.setAttribute('attr1', 'yes');
17+
Sentry.setExtra('requestHookCalled', {
18+
url: req.url,
19+
method: req.method,
20+
});
21+
},
22+
responseHook: (span, res) => {
23+
span.setAttribute('attr2', 'yes');
24+
Sentry.setExtra('responseHookCalled', {
25+
url: res.req.url,
26+
method: res.req.method,
27+
});
28+
},
29+
applyCustomAttributesOnSpan: (span, req, res) => {
30+
span.setAttribute('attr3', 'yes');
31+
Sentry.setExtra('applyCustomAttributesOnSpanCalled', {
32+
reqUrl: req.url,
33+
reqMethod: req.method,
34+
resUrl: res.req.url,
35+
resMethod: res.req.method,
36+
});
37+
},
38+
},
39+
}),
40+
],
41+
});

dev-packages/node-integration-tests/suites/tracing/httpIntegration/instrument.mjs

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,38 +4,6 @@ import { loggingTransport } from '@sentry-internal/node-integration-tests';
44
Sentry.init({
55
dsn: 'https://[email protected]/1337',
66
release: '1.0',
7-
// disable attaching headers to /test/* endpoints
8-
tracePropagationTargets: [/^(?!.*test).*$/],
97
tracesSampleRate: 1.0,
108
transport: loggingTransport,
11-
12-
integrations: [
13-
Sentry.httpIntegration({
14-
instrumentation: {
15-
requestHook: (span, req) => {
16-
span.setAttribute('attr1', 'yes');
17-
Sentry.setExtra('requestHookCalled', {
18-
url: req.url,
19-
method: req.method,
20-
});
21-
},
22-
responseHook: (span, res) => {
23-
span.setAttribute('attr2', 'yes');
24-
Sentry.setExtra('responseHookCalled', {
25-
url: res.req.url,
26-
method: res.req.method,
27-
});
28-
},
29-
applyCustomAttributesOnSpan: (span, req, res) => {
30-
span.setAttribute('attr3', 'yes');
31-
Sentry.setExtra('applyCustomAttributesOnSpanCalled', {
32-
reqUrl: req.url,
33-
reqMethod: req.method,
34-
resUrl: res.req.url,
35-
resMethod: res.req.method,
36-
});
37-
},
38-
},
39-
}),
40-
],
419
});

dev-packages/node-integration-tests/suites/tracing/httpIntegration/server.mjs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ app.get('/test', (_req, res) => {
1111
res.send({ response: 'response 1' });
1212
});
1313

14+
app.post('/test', (_req, res) => {
15+
res.send({ response: 'response 2' });
16+
});
17+
1418
Sentry.setupExpressErrorHandler(app);
1519

1620
startExpressServerAndSendPortToRunner(app);

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

Lines changed: 123 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,47 +7,134 @@ describe('httpIntegration', () => {
77
cleanupChildProcesses();
88
});
99

10-
createEsmAndCjsTests(__dirname, 'server.mjs', 'instrument.mjs', (createRunner, test) => {
11-
test('allows to pass instrumentation options to integration', async () => {
12-
const runner = createRunner()
13-
.expect({
14-
transaction: {
15-
contexts: {
16-
trace: {
17-
span_id: expect.stringMatching(/[a-f0-9]{16}/),
18-
trace_id: expect.stringMatching(/[a-f0-9]{32}/),
19-
data: {
10+
describe('instrumentation options', () => {
11+
createEsmAndCjsTests(__dirname, 'server.mjs', 'instrument-options.mjs', (createRunner, test) => {
12+
test('allows to pass instrumentation options to integration', async () => {
13+
const runner = createRunner()
14+
.expect({
15+
transaction: {
16+
contexts: {
17+
trace: {
18+
span_id: expect.stringMatching(/[a-f0-9]{16}/),
19+
trace_id: expect.stringMatching(/[a-f0-9]{32}/),
20+
data: {
21+
url: expect.stringMatching(/\/test$/),
22+
'http.response.status_code': 200,
23+
attr1: 'yes',
24+
attr2: 'yes',
25+
attr3: 'yes',
26+
},
27+
op: 'http.server',
28+
status: 'ok',
29+
},
30+
},
31+
extra: {
32+
requestHookCalled: {
2033
url: expect.stringMatching(/\/test$/),
21-
'http.response.status_code': 200,
22-
attr1: 'yes',
23-
attr2: 'yes',
24-
attr3: 'yes',
34+
method: 'GET',
35+
},
36+
responseHookCalled: {
37+
url: expect.stringMatching(/\/test$/),
38+
method: 'GET',
39+
},
40+
applyCustomAttributesOnSpanCalled: {
41+
reqUrl: expect.stringMatching(/\/test$/),
42+
reqMethod: 'GET',
43+
resUrl: expect.stringMatching(/\/test$/),
44+
resMethod: 'GET',
2545
},
26-
op: 'http.server',
27-
status: 'ok',
2846
},
2947
},
30-
extra: {
31-
requestHookCalled: {
32-
url: expect.stringMatching(/\/test$/),
33-
method: 'GET',
34-
},
35-
responseHookCalled: {
36-
url: expect.stringMatching(/\/test$/),
37-
method: 'GET',
38-
},
39-
applyCustomAttributesOnSpanCalled: {
40-
reqUrl: expect.stringMatching(/\/test$/),
41-
reqMethod: 'GET',
42-
resUrl: expect.stringMatching(/\/test$/),
43-
resMethod: 'GET',
44-
},
48+
})
49+
.start();
50+
runner.makeRequest('get', '/test');
51+
await runner.completed();
52+
});
53+
});
54+
});
55+
56+
describe('http.server spans', () => {
57+
createEsmAndCjsTests(__dirname, 'server.mjs', 'instrument.mjs', (createRunner, test) => {
58+
test('captures correct attributes for GET requests', async () => {
59+
const runner = createRunner()
60+
.expect({
61+
transaction: transaction => {
62+
const port = runner.getPort();
63+
expect(transaction.transaction).toBe('GET /test');
64+
expect(transaction.contexts?.trace?.data).toEqual({
65+
'http.flavor': '1.1',
66+
'http.host': `localhost:${port}`,
67+
'http.method': 'GET',
68+
'http.query': 'a=1&b=2',
69+
'http.response.status_code': 200,
70+
'http.route': '/test',
71+
'http.scheme': 'http',
72+
'http.status_code': 200,
73+
'http.status_text': 'OK',
74+
'http.target': '/test?a=1&b=2',
75+
'http.url': `http://localhost:${port}/test?a=1&b=2`,
76+
'http.user_agent': 'node',
77+
'net.host.ip': '::1',
78+
'net.host.name': 'localhost',
79+
'net.host.port': port,
80+
'net.peer.ip': '::1',
81+
'net.peer.port': expect.any(Number),
82+
'net.transport': 'ip_tcp',
83+
'otel.kind': 'SERVER',
84+
'sentry.op': 'http.server',
85+
'sentry.origin': 'auto.http.otel.http',
86+
'sentry.sample_rate': 1,
87+
'sentry.source': 'route',
88+
url: `http://localhost:${port}/test`,
89+
});
4590
},
46-
},
47-
})
48-
.start();
49-
runner.makeRequest('get', '/test');
50-
await runner.completed();
91+
})
92+
.start();
93+
94+
runner.makeRequest('get', '/test?a=1&b=2#hash');
95+
await runner.completed();
96+
});
97+
98+
test('captures correct attributes for POST requests', async () => {
99+
const runner = createRunner()
100+
.expect({
101+
transaction: transaction => {
102+
const port = runner.getPort();
103+
expect(transaction.transaction).toBe('POST /test');
104+
expect(transaction.contexts?.trace?.data).toEqual({
105+
'http.flavor': '1.1',
106+
'http.host': `localhost:${port}`,
107+
'http.method': 'POST',
108+
'http.query': 'a=1&b=2',
109+
'http.request_content_length_uncompressed': 9,
110+
'http.response.status_code': 200,
111+
'http.route': '/test',
112+
'http.scheme': 'http',
113+
'http.status_code': 200,
114+
'http.status_text': 'OK',
115+
'http.target': '/test?a=1&b=2',
116+
'http.url': `http://localhost:${port}/test?a=1&b=2`,
117+
'http.user_agent': 'node',
118+
'net.host.ip': '::1',
119+
'net.host.name': 'localhost',
120+
'net.host.port': port,
121+
'net.peer.ip': '::1',
122+
'net.peer.port': expect.any(Number),
123+
'net.transport': 'ip_tcp',
124+
'otel.kind': 'SERVER',
125+
'sentry.op': 'http.server',
126+
'sentry.origin': 'auto.http.otel.http',
127+
'sentry.sample_rate': 1,
128+
'sentry.source': 'route',
129+
url: `http://localhost:${port}/test`,
130+
});
131+
},
132+
})
133+
.start();
134+
135+
runner.makeRequest('post', '/test?a=1&b=2#hash', { data: 'test body' });
136+
await runner.completed();
137+
});
51138
});
52139
});
53140

dev-packages/node-integration-tests/utils/runner.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ type StartResult = {
158158
completed(): Promise<void>;
159159
childHasExited(): boolean;
160160
getLogs(): string[];
161+
getPort(): number | undefined;
161162
makeRequest<T>(
162163
method: 'get' | 'post',
163164
path: string,
@@ -617,6 +618,9 @@ export function createRunner(...paths: string[]) {
617618
getLogs(): string[] {
618619
return logs;
619620
},
621+
getPort(): number | undefined {
622+
return scenarioServerPort;
623+
},
620624
makeRequest: async function <T>(
621625
method: 'get' | 'post',
622626
path: string,

yarn.lock

Lines changed: 1 addition & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -6924,7 +6924,7 @@
69246924
mitt "^3.0.0"
69256925

69266926
"@sentry-internal/test-utils@link:dev-packages/test-utils":
6927-
version "10.2.0"
6927+
version "10.3.0"
69286928
dependencies:
69296929
express "^4.21.1"
69306930

@@ -6966,81 +6966,41 @@
69666966
magic-string "0.30.8"
69676967
unplugin "1.0.1"
69686968

6969-
6970-
version "2.49.0"
6971-
resolved "https://registry.yarnpkg.com/@sentry/cli-darwin/-/cli-darwin-2.49.0.tgz#290657e5840b360cb8ca25c8a78f8c0f15c66b03"
6972-
integrity sha512-bgowyDeFuXbjkGq1ZKqcWhmzgfBe7oKIXYWJOOps4+32QfG+YsrdNnottHS01td3bzrJq0QnHj8H12fA81DqrA==
6973-
69746969
69756970
version "2.50.2"
69766971
resolved "https://registry.yarnpkg.com/@sentry/cli-darwin/-/cli-darwin-2.50.2.tgz#fcf924fcc02cfa54748ff07a380334e533635c74"
69776972
integrity sha512-0Pjpl0vQqKhwuZm19z6AlEF+ds3fJg1KWabv8WzGaSc/fwxMEwjFwOZj+IxWBJPV578cXXNvB39vYjjpCH8j7A==
69786973

6979-
6980-
version "2.49.0"
6981-
resolved "https://registry.yarnpkg.com/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.49.0.tgz#a732004d7131f7e7b44f6a64abdccc36efb35d52"
6982-
integrity sha512-dqxsDUd76aDm03fUwUOs5BR7RHLpSb2EH/B1hlWm0mFvo9uY907XxW9wDFx/qDpCdmpC0aF+lF/lOBOrG9B5Fg==
6983-
69846974
69856975
version "2.50.2"
69866976
resolved "https://registry.yarnpkg.com/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.50.2.tgz#ac9e6dba42095832bac8084abab4b86fdd2956f3"
69876977
integrity sha512-03Cj215M3IdoHAwevCxm5oOm9WICFpuLR05DQnODFCeIUsGvE1pZsc+Gm0Ky/ZArq2PlShBJTpbHvXbCUka+0w==
69886978

6989-
6990-
version "2.49.0"
6991-
resolved "https://registry.yarnpkg.com/@sentry/cli-linux-arm/-/cli-linux-arm-2.49.0.tgz#73719561510df3369e05e9a4898b4e43b8753e4c"
6992-
integrity sha512-RBDIjIGmNsFw+a6vAt6m3D7ROKsMEB9i3u+UuIRxk0/DyHTcfVWxnK/ScPXGILM6PxQ2XOBfOKad0mmiDHBzZA==
6993-
69946979
69956980
version "2.50.2"
69966981
resolved "https://registry.yarnpkg.com/@sentry/cli-linux-arm/-/cli-linux-arm-2.50.2.tgz#835acd53ca83f6be9fc0d3d85a3cd4c694051bce"
69976982
integrity sha512-jzFwg9AeeuFAFtoCcyaDEPG05TU02uOy1nAX09c1g7FtsyQlPcbhI94JQGmnPzdRjjDmORtwIUiVZQrVTkDM7w==
69986983

6999-
7000-
version "2.49.0"
7001-
resolved "https://registry.yarnpkg.com/@sentry/cli-linux-i686/-/cli-linux-i686-2.49.0.tgz#8d1bb1378251a3aa995cc4b56bd352fa12a84b66"
7002-
integrity sha512-gDAd5/vJbEhd4Waud0Cd8ZRqLEagDlOvWwNH3KB694EiHJUwzRSiTA1YUVMYGI8Z9UyEA1sKxARwm2Trv99BxA==
7003-
70046984
70056985
version "2.50.2"
70066986
resolved "https://registry.yarnpkg.com/@sentry/cli-linux-i686/-/cli-linux-i686-2.50.2.tgz#72f0e4bc1c515754aa11225efce711a24fb53524"
70076987
integrity sha512-J+POvB34uVyHbIYF++Bc/OCLw+gqKW0H/y/mY7rRZCiocgpk266M4NtsOBl6bEaurMx1D+BCIEjr4nc01I/rqA==
70086988

7009-
7010-
version "2.49.0"
7011-
resolved "https://registry.yarnpkg.com/@sentry/cli-linux-x64/-/cli-linux-x64-2.49.0.tgz#7bf58fb7005c89fdde4e1262d5ed35e23065aceb"
7012-
integrity sha512-mbohGvPNhHjUciYNXzkt9TYUebTmxeAp9v9JfLSb/Soz6fubKwEHhpRJuz1zASxVWIR4PuqkePchqN5zhcLC0A==
7013-
70146989
70156990
version "2.50.2"
70166991
resolved "https://registry.yarnpkg.com/@sentry/cli-linux-x64/-/cli-linux-x64-2.50.2.tgz#d06f8ffd65871b1373a0d2228ab254d9456a615c"
70176992
integrity sha512-81yQVRLj8rnuHoYcrM7QbOw8ubA3weiMdPtTxTim1s6WExmPgnPTKxLCr9xzxGJxFdYo3xIOhtf5JFpUX/3j4A==
70186993

7019-
7020-
version "2.49.0"
7021-
resolved "https://registry.yarnpkg.com/@sentry/cli-win32-arm64/-/cli-win32-arm64-2.49.0.tgz#2bf6dd911acbe3ddb02eec0afb4301bb8fb25b53"
7022-
integrity sha512-3zwvsp61EPpSuGpGdXY4JelVJmNEjoj4vn5m6EFoOtk7OUI5/VFqqR4wchjy9Hjm3Eh6MB5K+KTKXs4W2p18ng==
7023-
70246994
70256995
version "2.50.2"
70266996
resolved "https://registry.yarnpkg.com/@sentry/cli-win32-arm64/-/cli-win32-arm64-2.50.2.tgz#4bd7a140367c17f77d621903cfe0914232108657"
70276997
integrity sha512-QjentLGvpibgiZlmlV9ifZyxV73lnGH6pFZWU5wLeRiaYKxWtNrrHpVs+HiWlRhkwQ0mG1/S40PGNgJ20DJ3gA==
70286998

7029-
7030-
version "2.49.0"
7031-
resolved "https://registry.yarnpkg.com/@sentry/cli-win32-i686/-/cli-win32-i686-2.49.0.tgz#32e31472ae6c5f69e538a4061d651937fcb8f14a"
7032-
integrity sha512-2oWaNl6z0BaOCAjM1Jxequfgjod3XO6wothxow4kA8e9+43JLhgarSdpwJPgQjcVyxjygwQ3/jKPdUFh0qNOmg==
7033-
70346999
70357000
version "2.50.2"
70367001
resolved "https://registry.yarnpkg.com/@sentry/cli-win32-i686/-/cli-win32-i686-2.50.2.tgz#1eb997cf780c396446cdd8e63c6d4309894465e8"
70377002
integrity sha512-UkBIIzkQkQ1UkjQX8kHm/+e7IxnEhK6CdgSjFyNlxkwALjDWHJjMztevqAPz3kv4LdM6q1MxpQ/mOqXICNhEGg==
70387003

7039-
7040-
version "2.49.0"
7041-
resolved "https://registry.yarnpkg.com/@sentry/cli-win32-x64/-/cli-win32-x64-2.49.0.tgz#86aab38cb41f885914d7c99ceaab7b6ce52c72c6"
7042-
integrity sha512-dR4ulyrA6ZT7x7cg4Rwm0tcHf4TZz5QO6t1W1jX6uJ9n/U0bOSqSFZHNf/RryiUzQE1g8LBthOYyKGMkET6T8w==
7043-
70447004
70457005
version "2.50.2"
70467006
resolved "https://registry.yarnpkg.com/@sentry/cli-win32-x64/-/cli-win32-x64-2.50.2.tgz#1d0c106125b6dc87f3a598ac02519c699f17a6c0"

0 commit comments

Comments
 (0)