Skip to content

Commit eb2d726

Browse files
author
Luca Forstner
authored
feat(nextjs): Add request data to all edge-capable functionalities (#9636)
1 parent 8c9ff6b commit eb2d726

22 files changed

+172
-26
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export const dynamic = 'force-dynamic';
2+
3+
export const runtime = 'edge';
4+
5+
export default async function Page() {
6+
return <h1>Hello world!</h1>;
7+
}

packages/e2e-tests/test-applications/nextjs-app-dir/sentry.client.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ Sentry.init({
55
dsn: process.env.NEXT_PUBLIC_E2E_TEST_DSN,
66
tunnel: `http://localhost:3031/`, // proxy server
77
tracesSampleRate: 1.0,
8+
sendDefaultPii: true,
89
});

packages/e2e-tests/test-applications/nextjs-app-dir/sentry.edge.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ Sentry.init({
55
dsn: process.env.NEXT_PUBLIC_E2E_TEST_DSN,
66
tunnel: `http://localhost:3031/`, // proxy server
77
tracesSampleRate: 1.0,
8+
sendDefaultPii: true,
89
});

packages/e2e-tests/test-applications/nextjs-app-dir/sentry.server.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ Sentry.init({
55
dsn: process.env.NEXT_PUBLIC_E2E_TEST_DSN,
66
tunnel: `http://localhost:3031/`, // proxy server
77
tracesSampleRate: 1.0,
8+
sendDefaultPii: true,
89
});

packages/e2e-tests/test-applications/nextjs-app-dir/tests/edge-route.test.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,19 @@ test('Should create a transaction for edge routes', async ({ request }) => {
88
);
99
});
1010

11-
const response = await request.get('/api/edge-endpoint');
11+
const response = await request.get('/api/edge-endpoint', {
12+
headers: {
13+
'x-yeet': 'test-value',
14+
},
15+
});
1216
expect(await response.json()).toStrictEqual({ name: 'Jim Halpert' });
1317

1418
const edgerouteTransaction = await edgerouteTransactionPromise;
1519

1620
expect(edgerouteTransaction.contexts?.trace?.status).toBe('ok');
1721
expect(edgerouteTransaction.contexts?.trace?.op).toBe('http.server');
1822
expect(edgerouteTransaction.contexts?.runtime?.name).toBe('vercel-edge');
23+
expect(edgerouteTransaction.request?.headers?.['x-yeet']).toBe('test-value');
1924
});
2025

2126
test('Should create a transaction with error status for faulty edge routes', async ({ request }) => {

packages/e2e-tests/test-applications/nextjs-app-dir/tests/edge.test.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { test, expect } from '@playwright/test';
2-
import { waitForError } from '../event-proxy-server';
2+
import { waitForError, waitForTransaction } from '../event-proxy-server';
33

44
test('Should record exceptions for faulty edge server components', async ({ page }) => {
55
const errorEventPromise = waitForError('nextjs-13-app-dir', errorEvent => {
@@ -10,3 +10,16 @@ test('Should record exceptions for faulty edge server components', async ({ page
1010

1111
expect(await errorEventPromise).toBeDefined();
1212
});
13+
14+
test('Should record transaction for edge server components', async ({ page }) => {
15+
const serverComponentTransactionPromise = waitForTransaction('nextjs-13-app-dir', async transactionEvent => {
16+
return transactionEvent?.transaction === 'Page Server Component (/edge-server-components)';
17+
});
18+
19+
await page.goto('/edge-server-components');
20+
21+
const serverComponentTransaction = await serverComponentTransactionPromise;
22+
23+
expect(serverComponentTransaction).toBeDefined();
24+
expect(serverComponentTransaction.request?.headers).toBeDefined();
25+
});

packages/e2e-tests/test-applications/nextjs-app-dir/tests/route-handlers.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@ test('Should create a transaction for route handlers', async ({ request }) => {
66
return transactionEvent?.transaction === 'GET /route-handlers/[param]';
77
});
88

9-
const response = await request.get('/route-handlers/foo');
9+
const response = await request.get('/route-handlers/foo', { headers: { 'x-yeet': 'test-value' } });
1010
expect(await response.json()).toStrictEqual({ name: 'John Doe' });
1111

1212
const routehandlerTransaction = await routehandlerTransactionPromise;
1313

1414
expect(routehandlerTransaction.contexts?.trace?.status).toBe('ok');
1515
expect(routehandlerTransaction.contexts?.trace?.op).toBe('http.server');
16+
expect(routehandlerTransaction.request?.headers?.['x-yeet']).toBe('test-value');
1617
});
1718

1819
test('Should create a transaction for route handlers and correctly set span status depending on http status', async ({

packages/e2e-tests/test-applications/nextjs-app-dir/tests/transactions.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ if (process.env.TEST_ENV === 'production') {
6363
const transactionEvent = await serverComponentTransactionPromise;
6464
const transactionEventId = transactionEvent.event_id;
6565

66+
expect(transactionEvent.request?.headers).toBeDefined();
67+
6668
await expect
6769
.poll(
6870
async () => {

packages/nextjs/src/common/types.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,38 @@
1-
import type { Transaction, WrappedFunction } from '@sentry/types';
1+
import type { Transaction, WebFetchHeaders, WrappedFunction } from '@sentry/types';
22
import type { NextApiRequest, NextApiResponse } from 'next';
33

44
export type ServerComponentContext = {
55
componentRoute: string;
66
componentType: string;
7+
// TODO(v8): Remove
8+
/**
9+
* @deprecated pass a complete `Headers` object with the `headers` field instead.
10+
*/
711
sentryTraceHeader?: string;
12+
// TODO(v8): Remove
13+
/**
14+
* @deprecated pass a complete `Headers` object with the `headers` field instead.
15+
*/
816
baggageHeader?: string;
17+
headers?: WebFetchHeaders;
918
};
1019

1120
export interface RouteHandlerContext {
21+
// TODO(v8): Remove
22+
/**
23+
* @deprecated The SDK will automatically pick up the method from the incoming Request object instead.
24+
*/
1225
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';
1326
parameterizedRoute: string;
27+
// TODO(v8): Remove
28+
/**
29+
* @deprecated The SDK will automatically pick up the `sentry-trace` header from the incoming Request object instead.
30+
*/
1431
sentryTraceHeader?: string;
32+
// TODO(v8): Remove
33+
/**
34+
* @deprecated The SDK will automatically pick up the `baggage` header from the incoming Request object instead.
35+
*/
1536
baggageHeader?: string;
1637
}
1738

packages/nextjs/src/common/utils/edgeWrapperUtils.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import { addTracingExtensions, captureException, flush, getCurrentHub, startTransaction } from '@sentry/core';
22
import type { Span } from '@sentry/types';
3-
import { addExceptionMechanism, logger, objectify, tracingContextFromHeaders } from '@sentry/utils';
3+
import {
4+
addExceptionMechanism,
5+
logger,
6+
objectify,
7+
tracingContextFromHeaders,
8+
winterCGRequestToRequestData,
9+
} from '@sentry/utils';
410

511
import type { EdgeRouteHandler } from '../../edge/types';
612

@@ -44,6 +50,7 @@ export function withEdgeWrapping<H extends EdgeRouteHandler>(
4450
origin: 'auto.ui.nextjs.withEdgeWrapping',
4551
...traceparentData,
4652
metadata: {
53+
request: winterCGRequestToRequestData(req),
4754
dynamicSamplingContext: traceparentData && !dynamicSamplingContext ? {} : dynamicSamplingContext,
4855
source: 'route',
4956
},

0 commit comments

Comments
 (0)