Skip to content

Commit 7c3ae66

Browse files
authored
Merge branch 'develop' into timfish/fix/improve-uuid-perf
2 parents 7acf3b7 + 9742f9e commit 7c3ae66

File tree

32 files changed

+1823
-18
lines changed

32 files changed

+1823
-18
lines changed

.size-limit.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ module.exports = [
7575
path: 'packages/browser/build/npm/esm/index.js',
7676
import: createImport('init', 'browserTracingIntegration', 'replayIntegration', 'replayCanvasIntegration'),
7777
gzip: true,
78-
limit: '84 KB',
78+
limit: '85 KB',
7979
},
8080
{
8181
name: '@sentry/browser (incl. Tracing, Replay, Feedback)',
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
@sentry:registry=http://127.0.0.1:4873
2+
@sentry-internal:registry=http://127.0.0.1:4873
3+
public-hoist-pattern[]=*import-in-the-middle*
4+
public-hoist-pattern[]=*require-in-the-middle*
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export function GET() {
2+
return Response.json({ name: 'John Doe' });
3+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
},
2323
"dependencies": {
2424
"@sentry/nextjs": "latest || *",
25+
"@sentry/core": "latest || *",
2526
"ai": "^3.0.0",
2627
"import-in-the-middle": "^1",
2728
"next": "16.0.0-beta.0",
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { getDefaultIsolationScope } from '@sentry/core';
2+
import * as Sentry from '@sentry/nextjs';
3+
import { NextResponse } from 'next/server';
4+
import type { NextRequest } from 'next/server';
5+
6+
export async function proxy(request: NextRequest) {
7+
Sentry.setTag('my-isolated-tag', true);
8+
Sentry.setTag('my-global-scope-isolated-tag', getDefaultIsolationScope().getScopeData().tags['my-isolated-tag']); // We set this tag to be able to assert that the previously set tag has not leaked into the global isolation scope
9+
10+
if (request.headers.has('x-should-throw')) {
11+
throw new Error('Middleware Error');
12+
}
13+
14+
if (request.headers.has('x-should-make-request')) {
15+
await fetch('http://localhost:3030/');
16+
}
17+
18+
return NextResponse.next();
19+
}
20+
21+
// See "Matching Paths" below to learn more
22+
export const config = {
23+
matcher: ['/api/endpoint-behind-middleware', '/api/endpoint-behind-faulty-middleware'],
24+
};

dev-packages/e2e-tests/test-applications/nextjs-16/sentry.edge.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ Sentry.init({
66
tunnel: `http://localhost:3031/`, // proxy server
77
tracesSampleRate: 1.0,
88
sendDefaultPii: true,
9+
// debug: true,
910
});

dev-packages/e2e-tests/test-applications/nextjs-16/sentry.server.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@ Sentry.init({
66
tunnel: `http://localhost:3031/`, // proxy server
77
tracesSampleRate: 1.0,
88
sendDefaultPii: true,
9+
// debug: true,
910
integrations: [Sentry.vercelAIIntegration()],
1011
});
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import { expect, test } from '@playwright/test';
2+
import { waitForError, waitForTransaction } from '@sentry-internal/test-utils';
3+
4+
test('Should create a transaction for middleware', async ({ request }) => {
5+
const middlewareTransactionPromise = waitForTransaction('nextjs-16', async transactionEvent => {
6+
return transactionEvent?.transaction === 'middleware GET';
7+
});
8+
9+
const response = await request.get('/api/endpoint-behind-middleware');
10+
expect(await response.json()).toStrictEqual({ name: 'John Doe' });
11+
12+
const middlewareTransaction = await middlewareTransactionPromise;
13+
14+
expect(middlewareTransaction.contexts?.trace?.status).toBe('ok');
15+
expect(middlewareTransaction.contexts?.trace?.op).toBe('http.server.middleware');
16+
expect(middlewareTransaction.contexts?.runtime?.name).toBe('vercel-edge');
17+
expect(middlewareTransaction.transaction_info?.source).toBe('url');
18+
19+
// Assert that isolation scope works properly
20+
expect(middlewareTransaction.tags?.['my-isolated-tag']).toBe(true);
21+
expect(middlewareTransaction.tags?.['my-global-scope-isolated-tag']).not.toBeDefined();
22+
});
23+
24+
test('Faulty middlewares', async ({ request }) => {
25+
const middlewareTransactionPromise = waitForTransaction('nextjs-16', async transactionEvent => {
26+
return transactionEvent?.transaction === 'middleware GET';
27+
});
28+
29+
const errorEventPromise = waitForError('nextjs-16', errorEvent => {
30+
return errorEvent?.exception?.values?.[0]?.value === 'Middleware Error';
31+
});
32+
33+
request.get('/api/endpoint-behind-middleware', { headers: { 'x-should-throw': '1' } }).catch(() => {
34+
// Noop
35+
});
36+
37+
await test.step('should record transactions', async () => {
38+
const middlewareTransaction = await middlewareTransactionPromise;
39+
expect(middlewareTransaction.contexts?.trace?.status).toBe('unknown_error');
40+
expect(middlewareTransaction.contexts?.trace?.op).toBe('http.server.middleware');
41+
expect(middlewareTransaction.contexts?.runtime?.name).toBe('vercel-edge');
42+
expect(middlewareTransaction.transaction_info?.source).toBe('url');
43+
});
44+
45+
await test.step('should record exceptions', async () => {
46+
const errorEvent = await errorEventPromise;
47+
48+
// Assert that isolation scope works properly
49+
expect(errorEvent.tags?.['my-isolated-tag']).toBe(true);
50+
expect(errorEvent.tags?.['my-global-scope-isolated-tag']).not.toBeDefined();
51+
expect([
52+
'middleware GET', // non-otel webpack versions
53+
'/middleware', // middleware file
54+
'/proxy', // proxy file
55+
]).toContain(errorEvent.transaction);
56+
});
57+
});
58+
59+
test('Should trace outgoing fetch requests inside middleware and create breadcrumbs for it', async ({ request }) => {
60+
const middlewareTransactionPromise = waitForTransaction('nextjs-16', async transactionEvent => {
61+
return (
62+
transactionEvent?.transaction === 'middleware GET' &&
63+
!!transactionEvent.spans?.find(span => span.op === 'http.client')
64+
);
65+
});
66+
67+
request.get('/api/endpoint-behind-middleware', { headers: { 'x-should-make-request': '1' } }).catch(() => {
68+
// Noop
69+
});
70+
71+
const middlewareTransaction = await middlewareTransactionPromise;
72+
73+
expect(middlewareTransaction.spans).toEqual(
74+
expect.arrayContaining([
75+
{
76+
data: {
77+
'http.method': 'GET',
78+
'http.response.status_code': 200,
79+
type: 'fetch',
80+
url: 'http://localhost:3030/',
81+
'http.url': 'http://localhost:3030/',
82+
'server.address': 'localhost:3030',
83+
'sentry.op': 'http.client',
84+
'sentry.origin': 'auto.http.wintercg_fetch',
85+
},
86+
description: 'GET http://localhost:3030/',
87+
op: 'http.client',
88+
origin: 'auto.http.wintercg_fetch',
89+
parent_span_id: expect.stringMatching(/[a-f0-9]{16}/),
90+
span_id: expect.stringMatching(/[a-f0-9]{16}/),
91+
start_timestamp: expect.any(Number),
92+
status: 'ok',
93+
timestamp: expect.any(Number),
94+
trace_id: expect.stringMatching(/[a-f0-9]{32}/),
95+
},
96+
]),
97+
);
98+
expect(middlewareTransaction.breadcrumbs).toEqual(
99+
expect.arrayContaining([
100+
{
101+
category: 'fetch',
102+
data: { method: 'GET', status_code: 200, url: 'http://localhost:3030/' },
103+
timestamp: expect.any(Number),
104+
type: 'http',
105+
},
106+
]),
107+
);
108+
});

dev-packages/e2e-tests/test-applications/nextjs-pages-dir/tests/middleware.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { waitForError, waitForTransaction } from '@sentry-internal/test-utils';
33

44
test('Should create a transaction for middleware', async ({ request }) => {
55
const middlewareTransactionPromise = waitForTransaction('nextjs-pages-dir', async transactionEvent => {
6-
return transactionEvent?.transaction === 'middleware GET /api/endpoint-behind-middleware';
6+
return transactionEvent?.transaction === 'middleware GET';
77
});
88

99
const response = await request.get('/api/endpoint-behind-middleware');
@@ -23,7 +23,7 @@ test('Should create a transaction for middleware', async ({ request }) => {
2323

2424
test('Faulty middlewares', async ({ request }) => {
2525
const middlewareTransactionPromise = waitForTransaction('nextjs-pages-dir', async transactionEvent => {
26-
return transactionEvent?.transaction === 'middleware GET /api/endpoint-behind-faulty-middleware';
26+
return transactionEvent?.transaction === 'middleware GET';
2727
});
2828

2929
const errorEventPromise = waitForError('nextjs-pages-dir', errorEvent => {
@@ -48,14 +48,14 @@ test('Faulty middlewares', async ({ request }) => {
4848
// Assert that isolation scope works properly
4949
expect(errorEvent.tags?.['my-isolated-tag']).toBe(true);
5050
expect(errorEvent.tags?.['my-global-scope-isolated-tag']).not.toBeDefined();
51-
expect(errorEvent.transaction).toBe('middleware GET /api/endpoint-behind-faulty-middleware');
51+
expect(errorEvent.transaction).toBe('middleware GET');
5252
});
5353
});
5454

5555
test('Should trace outgoing fetch requests inside middleware and create breadcrumbs for it', async ({ request }) => {
5656
const middlewareTransactionPromise = waitForTransaction('nextjs-pages-dir', async transactionEvent => {
5757
return (
58-
transactionEvent?.transaction === 'middleware GET /api/endpoint-behind-middleware' &&
58+
transactionEvent?.transaction === 'middleware GET' &&
5959
!!transactionEvent.spans?.find(span => span.op === 'http.client')
6060
);
6161
});

dev-packages/e2e-tests/test-applications/nuxt-3/nuxt.config.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,23 @@ export default defineNuxtConfig({
1212
},
1313
},
1414
nitro: {
15+
experimental: {
16+
database: true,
17+
},
18+
database: {
19+
default: {
20+
connector: 'sqlite',
21+
options: { name: 'db' },
22+
},
23+
users: {
24+
connector: 'sqlite',
25+
options: { name: 'users_db' },
26+
},
27+
analytics: {
28+
connector: 'sqlite',
29+
options: { name: 'analytics_db' },
30+
},
31+
},
1532
storage: {
1633
'test-storage': {
1734
driver: 'memory',

0 commit comments

Comments
 (0)