Skip to content

Commit ada32b2

Browse files
author
Luca Forstner
authored
ref(nextjs): Simplify wrapServerComponentWithSentry (#9844)
1 parent e1d3633 commit ada32b2

File tree

2 files changed

+51
-82
lines changed

2 files changed

+51
-82
lines changed

packages/core/src/tracing/trace.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ export function trace<T>(
2424
context: TransactionContext,
2525
callback: (span?: Span) => T,
2626
// eslint-disable-next-line @typescript-eslint/no-empty-function
27-
onError: (error: unknown) => void = () => {},
27+
onError: (error: unknown, span?: Span) => void = () => {},
28+
// eslint-disable-next-line @typescript-eslint/no-empty-function
29+
afterFinish: () => void = () => {},
2830
): T {
2931
const ctx = normalizeContext(context);
3032

@@ -46,24 +48,28 @@ export function trace<T>(
4648
maybePromiseResult = callback(activeSpan);
4749
} catch (e) {
4850
activeSpan && activeSpan.setStatus('internal_error');
49-
onError(e);
51+
onError(e, activeSpan);
5052
finishAndSetSpan();
53+
afterFinish();
5154
throw e;
5255
}
5356

5457
if (isThenable(maybePromiseResult)) {
5558
Promise.resolve(maybePromiseResult).then(
5659
() => {
5760
finishAndSetSpan();
61+
afterFinish();
5862
},
5963
e => {
6064
activeSpan && activeSpan.setStatus('internal_error');
61-
onError(e);
65+
onError(e, activeSpan);
6266
finishAndSetSpan();
67+
afterFinish();
6368
},
6469
);
6570
} else {
6671
finishAndSetSpan();
72+
afterFinish();
6773
}
6874

6975
return maybePromiseResult;

packages/nextjs/src/common/wrapServerComponentWithSentry.ts

Lines changed: 42 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
1-
import {
2-
addTracingExtensions,
3-
captureException,
4-
getCurrentScope,
5-
runWithAsyncContext,
6-
startTransaction,
7-
} from '@sentry/core';
8-
import { tracingContextFromHeaders, winterCGHeadersToDict } from '@sentry/utils';
1+
import { addTracingExtensions, captureException, continueTrace, runWithAsyncContext, trace } from '@sentry/core';
2+
import { winterCGHeadersToDict } from '@sentry/utils';
93

104
import { isNotFoundNavigationError, isRedirectNavigationError } from '../common/nextNavigationErrorUtils';
115
import type { ServerComponentContext } from '../common/types';
@@ -28,88 +22,57 @@ export function wrapServerComponentWithSentry<F extends (...args: any[]) => any>
2822
return new Proxy(appDirComponent, {
2923
apply: (originalFunction, thisArg, args) => {
3024
return runWithAsyncContext(() => {
31-
const currentScope = getCurrentScope();
32-
let maybePromiseResult;
33-
3425
const completeHeadersDict: Record<string, string> = context.headers
3526
? winterCGHeadersToDict(context.headers)
3627
: {};
3728

38-
const { traceparentData, dynamicSamplingContext, propagationContext } = tracingContextFromHeaders(
29+
const transactionContext = continueTrace({
3930
// eslint-disable-next-line deprecation/deprecation
40-
context.sentryTraceHeader ?? completeHeadersDict['sentry-trace'],
31+
sentryTrace: context.sentryTraceHeader ?? completeHeadersDict['sentry-trace'],
4132
// eslint-disable-next-line deprecation/deprecation
42-
context.baggageHeader ?? completeHeadersDict['baggage'],
43-
);
44-
currentScope.setPropagationContext(propagationContext);
45-
46-
const transaction = startTransaction({
47-
op: 'function.nextjs',
48-
name: `${componentType} Server Component (${componentRoute})`,
49-
status: 'ok',
50-
origin: 'auto.function.nextjs',
51-
...traceparentData,
52-
metadata: {
53-
request: {
54-
headers: completeHeadersDict,
55-
},
56-
source: 'component',
57-
dynamicSamplingContext: traceparentData && !dynamicSamplingContext ? {} : dynamicSamplingContext,
58-
},
33+
baggage: context.baggageHeader ?? completeHeadersDict['baggage'],
5934
});
6035

61-
currentScope.setSpan(transaction);
62-
63-
const handleErrorCase = (e: unknown): void => {
64-
if (isNotFoundNavigationError(e)) {
65-
// We don't want to report "not-found"s
66-
transaction.setStatus('not_found');
67-
} else if (isRedirectNavigationError(e)) {
68-
// We don't want to report redirects
69-
} else {
70-
transaction.setStatus('internal_error');
71-
72-
captureException(e, {
73-
mechanism: {
74-
handled: false,
36+
const res = trace(
37+
{
38+
...transactionContext,
39+
op: 'function.nextjs',
40+
name: `${componentType} Server Component (${componentRoute})`,
41+
status: 'ok',
42+
origin: 'auto.function.nextjs',
43+
metadata: {
44+
...transactionContext.metadata,
45+
request: {
46+
headers: completeHeadersDict,
7547
},
76-
});
77-
}
78-
79-
transaction.finish();
80-
};
81-
82-
try {
83-
maybePromiseResult = originalFunction.apply(thisArg, args);
84-
} catch (e) {
85-
handleErrorCase(e);
86-
void flushQueue();
87-
throw e;
88-
}
48+
source: 'component',
49+
},
50+
},
51+
() => originalFunction.apply(thisArg, args),
52+
(e, span) => {
53+
if (isNotFoundNavigationError(e)) {
54+
// We don't want to report "not-found"s
55+
span?.setStatus('not_found');
56+
} else if (isRedirectNavigationError(e)) {
57+
// We don't want to report redirects
58+
// Since `trace` will automatically set the span status to "internal_error" we need to set it back to "ok"
59+
span?.setStatus('ok');
60+
} else {
61+
span?.setStatus('internal_error');
8962

90-
if (typeof maybePromiseResult === 'object' && maybePromiseResult !== null && 'then' in maybePromiseResult) {
91-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
92-
Promise.resolve(maybePromiseResult)
93-
.then(
94-
() => {
95-
transaction.finish();
96-
},
97-
e => {
98-
handleErrorCase(e);
99-
},
100-
)
101-
.finally(() => {
102-
void flushQueue();
103-
});
63+
captureException(e, {
64+
mechanism: {
65+
handled: false,
66+
},
67+
});
68+
}
69+
},
70+
() => {
71+
void flushQueue();
72+
},
73+
);
10474

105-
// It is very important that we return the original promise here, because Next.js attaches various properties
106-
// to that promise and will throw if they are not on the returned value.
107-
return maybePromiseResult;
108-
} else {
109-
transaction.finish();
110-
void flushQueue();
111-
return maybePromiseResult;
112-
}
75+
return res;
11376
});
11477
},
11578
});

0 commit comments

Comments
 (0)