Skip to content

feat(nextjs): Add transactionName to isolation scope for Next.js server side features #11782

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ test('Should send a transaction and an error event for a faulty generateMetadata
const errorEvent = await errorEventPromise;
const transactionEvent = await transactionPromise;

expect(errorEvent.transaction).toBe('Page.generateMetadata (/generation-functions)');

// Assert that isolation scope works properly
expect(errorEvent.tags?.['my-isolated-tag']).toBe(true);
expect(errorEvent.tags?.['my-global-scope-isolated-tag']).not.toBeDefined();
Expand Down Expand Up @@ -82,6 +84,10 @@ test('Should send a transaction and an error event for a faulty generateViewport

expect(await transactionPromise).toBeDefined();
expect(await errorEventPromise).toBeDefined();

const errorEvent = await errorEventPromise;

expect(errorEvent.transaction).toBe('Page.generateViewport (/generation-functions)');
});

test('Should send a transaction event with correct status for a generateMetadata() function invokation with redirect()', async ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,6 @@ test('Should record exceptions for faulty edge routes', async ({ request }) => {
// Assert that isolation scope works properly
expect(errorEvent.tags?.['my-isolated-tag']).toBe(true);
expect(errorEvent.tags?.['my-global-scope-isolated-tag']).not.toBeDefined();

expect(errorEvent.transaction).toBe('GET /api/error-edge-endpoint');
});
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ test('Should record exceptions for faulty edge server components', async ({ page
// Assert that isolation scope works properly
expect(errorEvent.tags?.['my-isolated-tag']).toBe(true);
expect(errorEvent.tags?.['my-global-scope-isolated-tag']).not.toBeDefined();

expect(errorEvent.transaction).toBe(`Page Server Component (/edge-server-components/error)`);
});

test('Should record transaction for edge server components', async ({ page }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ test('Records exceptions happening in middleware', async ({ request }) => {
// Assert that isolation scope works properly
expect(errorEvent.tags?.['my-isolated-tag']).toBe(true);
expect(errorEvent.tags?.['my-global-scope-isolated-tag']).not.toBeDefined();
expect(errorEvent.transaction).toBe('middleware');
});

test('Should trace outgoing fetch requests inside middleware and create breadcrumbs for it', async ({ request }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ test('Should record exceptions and transactions for faulty route handlers', asyn
expect(routehandlerTransaction.contexts?.trace?.origin).toBe('auto.function.nextjs');

expect(routehandlerError.exception?.values?.[0].value).toBe('route-handler-error');
// TODO: Uncomment once we update the scope transaction name on the server side
// expect(routehandlerError.transaction).toBe('PUT /route-handlers/[param]/error');

expect(routehandlerError.transaction).toBe('PUT /route-handlers/[param]/error');
});

test.describe('Edge runtime', () => {
Expand Down Expand Up @@ -106,6 +106,8 @@ test.describe('Edge runtime', () => {

expect(routehandlerError.exception?.values?.[0].value).toBe('route-handler-edge-error');
expect(routehandlerError.contexts?.runtime?.name).toBe('vercel-edge');

expect(routehandlerError.transaction).toBe('DELETE /route-handlers/[param]/edge');
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ test('Should capture an error and transaction with correct status for a faulty s

expect(transactionEvent.contexts?.trace?.status).toBe('internal_error');

expect(errorEvent.transaction).toBe(`Page Server Component (/server-component/faulty)`);

expect(errorEvent.tags?.['my-isolated-tag']).toBe(true);
expect(errorEvent.tags?.['my-global-scope-isolated-tag']).not.toBeDefined();
expect(transactionEvent.tags?.['my-isolated-tag']).toBe(true);
Expand Down
2 changes: 2 additions & 0 deletions packages/nextjs/src/common/utils/edgeWrapperUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ export function withEdgeWrapping<H extends EdgeRouteHandler>(
});
}

isolationScope.setTransactionName(options.spanDescription);

return continueTrace(
{
sentryTrace,
Expand Down
1 change: 1 addition & 0 deletions packages/nextjs/src/common/utils/wrapperUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export function withTracedServerSideDataFetcher<F extends (...args: any[]) => Pr
return escapeNextjsTracing(() => {
const isolationScope = commonObjectToIsolationScope(req);
return withIsolationScope(isolationScope, () => {
isolationScope.setTransactionName(`${options.dataFetchingMethodName} (${options.dataFetcherRouteName})`);
isolationScope.setSDKProcessingMetadata({
request: req,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ async function withServerActionInstrumentationImplementation<A extends (...args:
);
}

isolationScope.setTransactionName(`serverAction/${serverActionName}`);
isolationScope.setSDKProcessingMetadata({
request: {
headers: fullHeadersObject,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export function wrapGenerationFunctionWithSentry<F extends (...args: any[]) => a
const propagationContext = commonObjectToPropagationContext(headers, incomingPropagationContext);

return withIsolationScope(isolationScope, () => {
isolationScope.setTransactionName(`${componentType}.${generationFunctionIdentifier} (${componentRoute})`);
isolationScope.setSDKProcessingMetadata({
request: {
headers: headers ? winterCGHeadersToDict(headers) : undefined,
Expand Down
1 change: 1 addition & 0 deletions packages/nextjs/src/common/wrapRouteHandlerWithSentry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export function wrapRouteHandlerWithSentry<F extends (...args: any[]) => any>(
const propagationContext = commonObjectToPropagationContext(headers, incomingPropagationContext);

return withIsolationScope(isolationScope, async () => {
isolationScope.setTransactionName(`${method} ${parameterizedRoute}`);
getCurrentScope().setPropagationContext(propagationContext);
try {
return startSpan(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export function wrapServerComponentWithSentry<F extends (...args: any[]) => any>
const propagationContext = commonObjectToPropagationContext(context.headers, incomingPropagationContext);

return withIsolationScope(isolationScope, () => {
isolationScope.setTransactionName(`${componentType} Server Component (${componentRoute})`);
getCurrentScope().setPropagationContext(propagationContext);
return startSpanManual(
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ describe('Error Server-side Props', () => {
});

expect(envelope[2]).toMatchObject({
transaction: `getServerSideProps (/withErrorServerSideProps)`,
exception: {
values: [
{
Expand Down