Skip to content

Commit 82b9756

Browse files
authored
feat(nextjs): Remove tracing from generation function template (#18733)
closes #18731
1 parent 0b0b904 commit 82b9756

File tree

2 files changed

+48
-100
lines changed

2 files changed

+48
-100
lines changed

dev-packages/e2e-tests/test-applications/nextjs-app-dir/tests/connected-servercomponent-trace.test.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ test('Will create a transaction with spans for every server component and metada
1717

1818
expect(spanDescriptions).toContainEqual('render route (app) /nested-layout');
1919
expect(spanDescriptions).toContainEqual('generateMetadata /(nested-layout)/nested-layout/page');
20-
expect(spanDescriptions).toContainEqual('Page.generateMetadata (/(nested-layout)/nested-layout)');
2120

2221
// Next.js 13 has limited OTEL support for server components, so we don't expect to see the following spans
2322
if (!isNext13) {
@@ -46,7 +45,6 @@ test('Will create a transaction with spans for every server component and metada
4645

4746
expect(spanDescriptions).toContainEqual('render route (app) /nested-layout/[dynamic]');
4847
expect(spanDescriptions).toContainEqual('generateMetadata /(nested-layout)/nested-layout/[dynamic]/page');
49-
expect(spanDescriptions).toContainEqual('Page.generateMetadata (/(nested-layout)/nested-layout/[dynamic])');
5048

5149
// Next.js 13 has limited OTEL support for server components, so we don't expect to see the following spans
5250
if (!isNext13) {
Lines changed: 48 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,133 +1,83 @@
1-
import type { RequestEventData, WebFetchHeaders } from '@sentry/core';
1+
import type { RequestEventData } from '@sentry/core';
22
import {
33
captureException,
44
getActiveSpan,
5-
getCapturedScopesOnSpan,
6-
getRootSpan,
5+
getIsolationScope,
76
handleCallbackErrors,
8-
propagationContextFromHeaders,
9-
Scope,
10-
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
11-
SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
12-
setCapturedScopesOnSpan,
137
SPAN_STATUS_ERROR,
148
SPAN_STATUS_OK,
15-
startSpanManual,
169
winterCGHeadersToDict,
17-
withIsolationScope,
18-
withScope,
1910
} from '@sentry/core';
2011
import type { GenerationFunctionContext } from '../common/types';
2112
import { isNotFoundNavigationError, isRedirectNavigationError } from './nextNavigationErrorUtils';
22-
import { TRANSACTION_ATTR_SENTRY_TRACE_BACKFILL } from './span-attributes-with-logic-attached';
23-
import { commonObjectToIsolationScope, commonObjectToPropagationContext } from './utils/tracingUtils';
13+
import { flushSafelyWithTimeout, waitUntil } from './utils/responseEnd';
14+
2415
/**
25-
* Wraps a generation function (e.g. generateMetadata) with Sentry error and performance instrumentation.
16+
* Wraps a generation function (e.g. generateMetadata) with Sentry error instrumentation.
2617
*/
2718
// eslint-disable-next-line @typescript-eslint/no-explicit-any
2819
export function wrapGenerationFunctionWithSentry<F extends (...args: any[]) => any>(
2920
generationFunction: F,
3021
context: GenerationFunctionContext,
3122
): F {
32-
const { requestAsyncStorage, componentRoute, componentType, generationFunctionIdentifier } = context;
3323
return new Proxy(generationFunction, {
3424
apply: (originalFunction, thisArg, args) => {
35-
const requestTraceId = getActiveSpan()?.spanContext().traceId;
36-
let headers: WebFetchHeaders | undefined = undefined;
37-
// We try-catch here just in case anything goes wrong with the async storage here goes wrong since it is Next.js internal API
25+
const isolationScope = getIsolationScope();
26+
27+
let headers = undefined;
28+
// We try-catch here just in case anything goes wrong with the async storage since it is Next.js internal API
3829
try {
39-
headers = requestAsyncStorage?.getStore()?.headers;
30+
headers = context.requestAsyncStorage?.getStore()?.headers;
4031
} catch {
4132
/** empty */
4233
}
4334

44-
const isolationScope = commonObjectToIsolationScope(headers);
45-
46-
const activeSpan = getActiveSpan();
47-
if (activeSpan) {
48-
const rootSpan = getRootSpan(activeSpan);
49-
const { scope } = getCapturedScopesOnSpan(rootSpan);
50-
setCapturedScopesOnSpan(rootSpan, scope ?? new Scope(), isolationScope);
51-
}
52-
5335
const headersDict = headers ? winterCGHeadersToDict(headers) : undefined;
5436

55-
return withIsolationScope(isolationScope, () => {
56-
return withScope(scope => {
57-
scope.setTransactionName(`${componentType}.${generationFunctionIdentifier} (${componentRoute})`);
37+
isolationScope.setSDKProcessingMetadata({
38+
normalizedRequest: {
39+
headers: headersDict,
40+
} satisfies RequestEventData,
41+
});
5842

59-
isolationScope.setSDKProcessingMetadata({
60-
normalizedRequest: {
61-
headers: headersDict,
62-
} satisfies RequestEventData,
63-
});
43+
return handleCallbackErrors(
44+
() => originalFunction.apply(thisArg, args),
45+
error => {
46+
const span = getActiveSpan();
47+
const { componentRoute, componentType, generationFunctionIdentifier } = context;
48+
let shouldCapture = true;
49+
isolationScope.setTransactionName(`${componentType}.${generationFunctionIdentifier} (${componentRoute})`);
6450

65-
const activeSpan = getActiveSpan();
66-
if (activeSpan) {
67-
const rootSpan = getRootSpan(activeSpan);
68-
const sentryTrace = headersDict?.['sentry-trace'];
69-
if (sentryTrace) {
70-
rootSpan.setAttribute(TRANSACTION_ATTR_SENTRY_TRACE_BACKFILL, sentryTrace);
51+
if (span) {
52+
if (isNotFoundNavigationError(error)) {
53+
// We don't want to report "not-found"s
54+
shouldCapture = false;
55+
span.setStatus({ code: SPAN_STATUS_ERROR, message: 'not_found' });
56+
} else if (isRedirectNavigationError(error)) {
57+
// We don't want to report redirects
58+
shouldCapture = false;
59+
span.setStatus({ code: SPAN_STATUS_OK });
60+
} else {
61+
span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });
7162
}
7263
}
7364

74-
const propagationContext = commonObjectToPropagationContext(
75-
headers,
76-
propagationContextFromHeaders(headersDict?.['sentry-trace'], headersDict?.['baggage']),
77-
);
78-
79-
if (requestTraceId) {
80-
propagationContext.traceId = requestTraceId;
81-
}
82-
83-
scope.setPropagationContext(propagationContext);
84-
85-
return startSpanManual(
86-
{
87-
op: 'function.nextjs',
88-
name: `${componentType}.${generationFunctionIdentifier} (${componentRoute})`,
89-
attributes: {
90-
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',
91-
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.nextjs',
92-
'sentry.nextjs.ssr.function.type': generationFunctionIdentifier,
93-
'sentry.nextjs.ssr.function.route': componentRoute,
94-
},
95-
},
96-
span => {
97-
return handleCallbackErrors(
98-
() => originalFunction.apply(thisArg, args),
99-
err => {
100-
// When you read this code you might think: "Wait a minute, shouldn't we set the status on the root span too?"
101-
// The answer is: "No." - The status of the root span is determined by whatever status code Next.js decides to put on the response.
102-
if (isNotFoundNavigationError(err)) {
103-
// We don't want to report "not-found"s
104-
span.setStatus({ code: SPAN_STATUS_ERROR, message: 'not_found' });
105-
getRootSpan(span).setStatus({ code: SPAN_STATUS_ERROR, message: 'not_found' });
106-
} else if (isRedirectNavigationError(err)) {
107-
// We don't want to report redirects
108-
span.setStatus({ code: SPAN_STATUS_OK });
109-
} else {
110-
span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });
111-
getRootSpan(span).setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });
112-
captureException(err, {
113-
mechanism: {
114-
handled: false,
115-
type: 'auto.function.nextjs.generation_function',
116-
data: {
117-
function: generationFunctionIdentifier,
118-
},
119-
},
120-
});
121-
}
122-
},
123-
() => {
124-
span.end();
65+
if (shouldCapture) {
66+
captureException(error, {
67+
mechanism: {
68+
handled: false,
69+
type: 'auto.function.nextjs.generation_function',
70+
data: {
71+
function: generationFunctionIdentifier,
12572
},
126-
);
127-
},
128-
);
129-
});
130-
});
73+
},
74+
});
75+
}
76+
},
77+
() => {
78+
waitUntil(flushSafelyWithTimeout());
79+
},
80+
);
13181
},
13282
});
13383
}

0 commit comments

Comments
 (0)