Skip to content

Commit 85da8cf

Browse files
s1gr1dmydea
andauthored
feat(nextjs): Add transaction name to scope of server component (#11850)
ref #11782 --------- Co-authored-by: Francesco Novy <francesco.novy@sentry.io>
1 parent ae17054 commit 85da8cf

File tree

3 files changed

+46
-43
lines changed

3 files changed

+46
-43
lines changed

packages/nextjs/src/common/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import type { RequestAsyncStorage } from '../config/templates/requestAsyncStorag
55

66
export type ServerComponentContext = {
77
componentRoute: string;
8-
componentType: string;
8+
componentType: 'Page' | 'Layout' | 'Head' | 'Not-found' | 'Loading' | 'Unknown';
99
headers?: WebFetchHeaders;
1010
};
1111

packages/nextjs/src/common/wrapServerComponentWithSentry.ts

Lines changed: 43 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ import {
33
SPAN_STATUS_ERROR,
44
SPAN_STATUS_OK,
55
captureException,
6-
getCurrentScope,
76
handleCallbackErrors,
87
startSpanManual,
98
withIsolationScope,
9+
withScope,
1010
} from '@sentry/core';
1111
import { propagationContextFromHeaders, winterCGHeadersToDict } from '@sentry/utils';
1212

@@ -55,47 +55,50 @@ export function wrapServerComponentWithSentry<F extends (...args: any[]) => any>
5555
const propagationContext = commonObjectToPropagationContext(context.headers, incomingPropagationContext);
5656

5757
return withIsolationScope(isolationScope, () => {
58-
isolationScope.setTransactionName(`${componentType} Server Component (${componentRoute})`);
59-
getCurrentScope().setPropagationContext(propagationContext);
60-
return startSpanManual(
61-
{
62-
op: 'function.nextjs',
63-
name: `${componentType} Server Component (${componentRoute})`,
64-
forceTransaction: true,
65-
attributes: {
66-
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'component',
67-
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.nextjs',
68-
},
69-
},
70-
span => {
71-
return handleCallbackErrors(
72-
() => originalFunction.apply(thisArg, args),
73-
error => {
74-
if (isNotFoundNavigationError(error)) {
75-
// We don't want to report "not-found"s
76-
span.setStatus({ code: SPAN_STATUS_ERROR, message: 'not_found' });
77-
} else if (isRedirectNavigationError(error)) {
78-
// We don't want to report redirects
79-
span.setStatus({ code: SPAN_STATUS_OK });
80-
} else {
81-
span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });
82-
captureException(error, {
83-
mechanism: {
84-
handled: false,
85-
},
86-
});
87-
}
88-
},
89-
() => {
90-
span.end();
58+
return withScope(scope => {
59+
scope.setTransactionName(`${componentType} Server Component (${componentRoute})`);
9160

92-
// flushQueue should not throw
93-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
94-
flushQueue();
61+
scope.setPropagationContext(propagationContext);
62+
return startSpanManual(
63+
{
64+
op: 'function.nextjs',
65+
name: `${componentType} Server Component (${componentRoute})`,
66+
forceTransaction: true,
67+
attributes: {
68+
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'component',
69+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.nextjs',
9570
},
96-
);
97-
},
98-
);
71+
},
72+
span => {
73+
return handleCallbackErrors(
74+
() => originalFunction.apply(thisArg, args),
75+
error => {
76+
if (isNotFoundNavigationError(error)) {
77+
// We don't want to report "not-found"s
78+
span.setStatus({ code: SPAN_STATUS_ERROR, message: 'not_found' });
79+
} else if (isRedirectNavigationError(error)) {
80+
// We don't want to report redirects
81+
span.setStatus({ code: SPAN_STATUS_OK });
82+
} else {
83+
span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });
84+
captureException(error, {
85+
mechanism: {
86+
handled: false,
87+
},
88+
});
89+
}
90+
},
91+
() => {
92+
span.end();
93+
94+
// flushQueue should not throw
95+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
96+
flushQueue();
97+
},
98+
);
99+
},
100+
);
101+
});
99102
});
100103
});
101104
},

packages/nextjs/src/config/loaders/wrappingLoader.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import * as chalk from 'chalk';
66
import type { RollupBuild, RollupError } from 'rollup';
77
import { rollup } from 'rollup';
88

9-
import type { VercelCronsConfig } from '../../common/types';
9+
import type { ServerComponentContext, VercelCronsConfig } from '../../common/types';
1010
import type { LoaderThis } from './types';
1111

1212
// Just a simple placeholder to make referencing module consistent
@@ -185,7 +185,7 @@ export default function wrappingLoader(
185185
.match(/\/?([^/]+)\.(?:js|ts|jsx|tsx)$/);
186186

187187
if (componentTypeMatch && componentTypeMatch[1]) {
188-
let componentType;
188+
let componentType: ServerComponentContext['componentType'];
189189
switch (componentTypeMatch[1]) {
190190
case 'page':
191191
componentType = 'Page';

0 commit comments

Comments
 (0)