Skip to content

Commit b78f8da

Browse files
author
Luca Forstner
authored
Merge branch 'develop' into lforst-nextjs-otel
2 parents 83d90f7 + 8d5a084 commit b78f8da

File tree

14 files changed

+312
-92
lines changed

14 files changed

+312
-92
lines changed

.size-limit.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ module.exports = [
7979
path: 'packages/browser/build/npm/esm/index.js',
8080
import: createImport('init', 'browserTracingIntegration', 'replayIntegration', 'replayCanvasIntegration'),
8181
gzip: true,
82-
limit: '78 KB',
82+
limit: '78.1 KB',
8383
},
8484
{
8585
name: '@sentry/browser (incl. Tracing, Replay, Feedback)',
@@ -138,7 +138,7 @@ module.exports = [
138138
import: createImport('init', 'ErrorBoundary', 'reactRouterV6BrowserTracingIntegration'),
139139
ignore: ['react/jsx-runtime'],
140140
gzip: true,
141-
limit: '39 KB',
141+
limit: '39.05 KB',
142142
},
143143
// Vue SDK (ESM)
144144
{
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import * as Sentry from '@sentry/browser';
2+
3+
window.Sentry = Sentry;
4+
5+
Sentry.init({
6+
dsn: 'https://public@dsn.ingest.sentry.io/1337',
7+
integrations: [Sentry.browserTracingIntegration()],
8+
tracePropagationTargets: ['http://example.com'],
9+
tracesSampleRate: 1,
10+
});
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
fetchPojo.addEventListener('click', () => {
2+
const fetchOptions = {
3+
headers: {
4+
'sentry-trace': '12312012123120121231201212312012-1121201211212012-1',
5+
baggage: 'sentry-release=4.2.0',
6+
},
7+
};
8+
9+
// Make two fetch requests that reuse the same fetch object
10+
Sentry.startSpan({ name: 'does-not-matter-1' }, () =>
11+
fetch('http://example.com/fetch-pojo', fetchOptions)
12+
.then(res => res.text())
13+
.then(() =>
14+
Sentry.startSpan({ name: 'does-not-matter-2' }, () => fetch('http://example.com/fetch-pojo', fetchOptions)),
15+
),
16+
);
17+
});
18+
19+
fetchArray.addEventListener('click', () => {
20+
const fetchOptions = {
21+
headers: [
22+
['sentry-trace', '12312012123120121231201212312012-1121201211212012-1'],
23+
['baggage', 'sentry-release=4.2.0'],
24+
],
25+
};
26+
27+
// Make two fetch requests that reuse the same fetch object
28+
Sentry.startSpan({ name: 'does-not-matter-1' }, () =>
29+
fetch('http://example.com/fetch-array', fetchOptions)
30+
.then(res => res.text())
31+
.then(() =>
32+
Sentry.startSpan({ name: 'does-not-matter-2' }, () => fetch('http://example.com/fetch-array', fetchOptions)),
33+
),
34+
);
35+
});
36+
37+
fetchHeaders.addEventListener('click', () => {
38+
const fetchOptions = {
39+
headers: new Headers({
40+
'sentry-trace': '12312012123120121231201212312012-1121201211212012-1',
41+
baggage: 'sentry-release=4.2.0',
42+
}),
43+
};
44+
45+
// Make two fetch requests that reuse the same fetch object
46+
Sentry.startSpan({ name: 'does-not-matter-1' }, () =>
47+
fetch('http://example.com/fetch-headers', fetchOptions)
48+
.then(res => res.text())
49+
.then(() =>
50+
Sentry.startSpan({ name: 'does-not-matter-2' }, () => fetch('http://example.com/fetch-headers', fetchOptions)),
51+
),
52+
);
53+
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8" />
5+
</head>
6+
<body>
7+
<button id="fetchPojo">Fetch POJO</button>
8+
<button id="fetchArray">Fetch array</button>
9+
<button id="fetchHeaders">Fetch Headers</button>
10+
</body>
11+
</html>
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import type { Page, Request } from '@playwright/test';
2+
import { expect } from '@playwright/test';
3+
import { sentryTest } from '../../../../utils/fixtures';
4+
import { shouldSkipTracingTest } from '../../../../utils/helpers';
5+
6+
async function assertRequests({
7+
page,
8+
buttonSelector,
9+
requestMatcher,
10+
}: { page: Page; buttonSelector: string; requestMatcher: string }) {
11+
const requests = await new Promise<Request[]>(resolve => {
12+
const requests: Request[] = [];
13+
page
14+
.route(requestMatcher, (route, request) => {
15+
requests.push(request);
16+
if (requests.length === 2) {
17+
resolve(requests);
18+
}
19+
20+
return route.fulfill({
21+
status: 200,
22+
contentType: 'application/json',
23+
body: JSON.stringify({}),
24+
});
25+
})
26+
.then(() => {
27+
page.click(buttonSelector);
28+
});
29+
});
30+
31+
requests.forEach(request => {
32+
const headers = request.headers();
33+
34+
// No merged sentry trace headers
35+
expect(headers['sentry-trace']).not.toContain(',');
36+
37+
// No multiple baggage entries
38+
expect(headers['baggage'].match(/sentry-trace_id/g) ?? []).toHaveLength(1);
39+
});
40+
}
41+
42+
sentryTest(
43+
'Ensure the SDK does not infinitely append tracing headers to outgoing requests',
44+
async ({ getLocalTestUrl, page }) => {
45+
if (shouldSkipTracingTest()) {
46+
sentryTest.skip();
47+
}
48+
49+
const url = await getLocalTestUrl({ testDir: __dirname });
50+
await page.goto(url);
51+
52+
await sentryTest.step('fetch with POJO', () =>
53+
assertRequests({ page, buttonSelector: '#fetchPojo', requestMatcher: 'http://example.com/fetch-pojo' }),
54+
);
55+
56+
await sentryTest.step('fetch with array', () =>
57+
assertRequests({ page, buttonSelector: '#fetchArray', requestMatcher: 'http://example.com/fetch-array' }),
58+
);
59+
60+
await sentryTest.step('fetch with Headers instance', () =>
61+
assertRequests({ page, buttonSelector: '#fetchHeaders', requestMatcher: 'http://example.com/fetch-headers' }),
62+
);
63+
},
64+
);

dev-packages/e2e-tests/test-applications/nextjs-15/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
"test:dev": "TEST_ENV=development playwright test",
1010
"test:build": "pnpm install && npx playwright install && pnpm build",
1111
"test:build-canary": "pnpm install && pnpm add next@canary && pnpm add react@beta && pnpm add react-dom@beta && npx playwright install && pnpm build",
12-
"test:build-latest": "pnpm install && pnpm add next@rc && pnpm add react@beta && pnpm add react-dom@beta && npx playwright install && pnpm build",
12+
"//": "15.0.0-canary.194 is the canary release attached to Next.js RC 1. We need to use the canary version instead of the RC because PPR will not work without. The specific react version is also attached to RC 1.",
13+
"test:build-latest": "pnpm install && pnpm add next@15.0.0-canary.194 && pnpm add react@19.0.0-rc-cd22717c-20241013 && pnpm add react-dom@19.0.0-rc-cd22717c-20241013 && npx playwright install && pnpm build",
1314
"test:assert": "pnpm test:prod && pnpm test:dev"
1415
},
1516
"dependencies": {

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

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@ Sentry.init({
1111
integrations: [
1212
Sentry.httpIntegration({
1313
ignoreOutgoingRequests: (url, request) => {
14-
if (url.includes('example.com')) {
14+
if (url === 'http://example.com/blockUrl') {
1515
return true;
1616
}
17-
if (request.method === 'POST' && request.path === '/path') {
17+
18+
if (request.hostname === 'example.com' && request.path === '/blockRequest') {
1819
return true;
1920
}
2021
return false;
@@ -32,28 +33,37 @@ const app = express();
3233

3334
app.use(cors());
3435

35-
app.get('/test', (_req, response) => {
36-
http
37-
.request('http://example.com/', res => {
38-
res.on('data', () => {});
39-
res.on('end', () => {
40-
response.send({ response: 'done' });
41-
});
42-
})
43-
.end();
36+
app.get('/testUrl', (_req, response) => {
37+
makeHttpRequest('http://example.com/blockUrl').then(() => {
38+
makeHttpRequest('http://example.com/pass').then(() => {
39+
response.send({ response: 'done' });
40+
});
41+
});
4442
});
4543

46-
app.post('/testPath', (_req, response) => {
47-
http
48-
.request('http://example.com/path', res => {
49-
res.on('data', () => {});
50-
res.on('end', () => {
51-
response.send({ response: 'done' });
52-
});
53-
})
54-
.end();
44+
app.get('/testRequest', (_req, response) => {
45+
makeHttpRequest('http://example.com/blockRequest').then(() => {
46+
makeHttpRequest('http://example.com/pass').then(() => {
47+
response.send({ response: 'done' });
48+
});
49+
});
5550
});
5651

5752
Sentry.setupExpressErrorHandler(app);
5853

5954
startExpressServerAndSendPortToRunner(app);
55+
56+
function makeHttpRequest(url) {
57+
return new Promise((resolve, reject) => {
58+
http
59+
.get(url, res => {
60+
res.on('data', () => {});
61+
res.on('end', () => {
62+
resolve();
63+
});
64+
})
65+
.on('error', error => {
66+
reject(error);
67+
});
68+
});
69+
}

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

Lines changed: 23 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -128,65 +128,45 @@ describe('httpIntegration', () => {
128128
});
129129
});
130130

131-
describe("doesn't create child spans for outgoing requests ignored via `ignoreOutgoingRequests`", () => {
131+
describe("doesn't create child spans or breadcrumbs for outgoing requests ignored via `ignoreOutgoingRequests`", () => {
132132
test('via the url param', done => {
133133
const runner = createRunner(__dirname, 'server-ignoreOutgoingRequests.js')
134134
.expect({
135-
transaction: {
136-
contexts: {
137-
trace: {
138-
span_id: expect.any(String),
139-
trace_id: expect.any(String),
140-
data: {
141-
url: expect.stringMatching(/\/test$/),
142-
'http.response.status_code': 200,
143-
},
144-
op: 'http.server',
145-
status: 'ok',
146-
},
147-
},
148-
transaction: 'GET /test',
149-
spans: [
150-
expect.objectContaining({ op: 'middleware.express', description: 'query' }),
151-
expect.objectContaining({ op: 'middleware.express', description: 'expressInit' }),
152-
expect.objectContaining({ op: 'middleware.express', description: 'corsMiddleware' }),
153-
expect.objectContaining({ op: 'request_handler.express', description: '/test' }),
154-
],
135+
transaction: event => {
136+
expect(event.transaction).toBe('GET /testUrl');
137+
138+
const requestSpans = event.spans?.filter(span => span.op === 'http.client');
139+
expect(requestSpans).toHaveLength(1);
140+
expect(requestSpans![0]?.description).toBe('GET http://example.com/pass');
141+
142+
const breadcrumbs = event.breadcrumbs?.filter(b => b.category === 'http');
143+
expect(breadcrumbs).toHaveLength(1);
144+
expect(breadcrumbs![0]?.data?.url).toEqual('http://example.com/pass');
155145
},
156146
})
157147
.start(done);
158148

159-
runner.makeRequest('get', '/test');
149+
runner.makeRequest('get', '/testUrl');
160150
});
161151

162152
test('via the request param', done => {
163153
const runner = createRunner(__dirname, 'server-ignoreOutgoingRequests.js')
164154
.expect({
165-
transaction: {
166-
contexts: {
167-
trace: {
168-
span_id: expect.any(String),
169-
trace_id: expect.any(String),
170-
data: {
171-
url: expect.stringMatching(/\/testPath$/),
172-
'http.response.status_code': 200,
173-
},
174-
op: 'http.server',
175-
status: 'ok',
176-
},
177-
},
178-
transaction: 'POST /testPath',
179-
spans: [
180-
expect.objectContaining({ op: 'middleware.express', description: 'query' }),
181-
expect.objectContaining({ op: 'middleware.express', description: 'expressInit' }),
182-
expect.objectContaining({ op: 'middleware.express', description: 'corsMiddleware' }),
183-
expect.objectContaining({ op: 'request_handler.express', description: '/testPath' }),
184-
],
155+
transaction: event => {
156+
expect(event.transaction).toBe('GET /testRequest');
157+
158+
const requestSpans = event.spans?.filter(span => span.op === 'http.client');
159+
expect(requestSpans).toHaveLength(1);
160+
expect(requestSpans![0]?.description).toBe('GET http://example.com/pass');
161+
162+
const breadcrumbs = event.breadcrumbs?.filter(b => b.category === 'http');
163+
expect(breadcrumbs).toHaveLength(1);
164+
expect(breadcrumbs![0]?.data?.url).toEqual('http://example.com/pass');
185165
},
186166
})
187167
.start(done);
188168

189-
runner.makeRequest('post', '/testPath');
169+
runner.makeRequest('get', '/testRequest');
190170
});
191171
});
192172
});

0 commit comments

Comments
 (0)