Skip to content

Commit e13abef

Browse files
author
Luca Forstner
committed
Extract dropping utility into separate function
1 parent 4fc4320 commit e13abef

File tree

7 files changed

+36
-76
lines changed

7 files changed

+36
-76
lines changed

packages/nextjs/src/common/pages-router-instrumentation/wrapApiHandlerWithSentry.ts

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ import {
33
SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
44
captureException,
55
continueTrace,
6-
getActiveSpan,
7-
getRootSpan,
86
setHttpStatus,
97
startSpanManual,
108
withIsolationScope,
@@ -13,10 +11,9 @@ import { isString, logger, objectify } from '@sentry/utils';
1311

1412
import { vercelWaitUntil } from '@sentry/utils';
1513
import type { NextApiRequest } from 'next';
16-
import { TRANSACTION_ATTR_SHOULD_DROP_TRANSACTION } from '../span-attributes-with-logic-attached';
1714
import type { AugmentedNextApiResponse, NextApiHandler } from '../types';
1815
import { flushSafelyWithTimeout } from '../utils/responseEnd';
19-
import { escapeNextjsTracing } from '../utils/tracingUtils';
16+
import { dropNextjsRootContext, escapeNextjsTracing } from '../utils/tracingUtils';
2017

2118
export type AugmentedNextApiRequest = NextApiRequest & {
2219
__withSentry_applied__?: boolean;
@@ -31,21 +28,13 @@ export type AugmentedNextApiRequest = NextApiRequest & {
3128
* @returns The wrapped handler which will always return a Promise.
3229
*/
3330
export function wrapApiHandlerWithSentry(apiHandler: NextApiHandler, parameterizedRoute: string): NextApiHandler {
34-
// Since the API route handler spans emitted by Next.js are super buggy with completely wrong timestamps
35-
// (fix pending at the time of writing this: https://github.com/vercel/next.js/pull/70908) we want to intentionally
36-
// drop them. In the future, when Next.js' OTEL instrumentation is in a high-quality place we can potentially think
37-
// about keeping them.
38-
const nextJsOwnedSpan = getActiveSpan();
39-
if (nextJsOwnedSpan) {
40-
getRootSpan(nextJsOwnedSpan)?.setAttribute(TRANSACTION_ATTR_SHOULD_DROP_TRANSACTION, true);
41-
}
42-
4331
return new Proxy(apiHandler, {
4432
apply: (
4533
wrappingTarget,
4634
thisArg,
4735
args: [AugmentedNextApiRequest | undefined, AugmentedNextApiResponse | undefined],
4836
) => {
37+
dropNextjsRootContext();
4938
return escapeNextjsTracing(() => {
5039
const [req, res] = args;
5140

packages/nextjs/src/common/pages-router-instrumentation/wrapApiHandlerWithSentryVercelCrons.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ type EdgeRequest = {
99
};
1010

1111
/**
12-
* Wraps a function with Sentry crons instrumentation by automaticaly sending check-ins for the given Vercel crons config.
12+
* Wraps a function with Sentry crons instrumentation by automatically sending check-ins for the given Vercel crons config.
1313
*/
1414
// eslint-disable-next-line @typescript-eslint/no-explicit-any
1515
export function wrapApiHandlerWithSentryVercelCrons<F extends (...args: any[]) => any>(

packages/nextjs/src/common/pages-router-instrumentation/wrapPageComponentWithSentry.ts

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import { captureException, getActiveSpan, getCurrentScope, getRootSpan, withIsolationScope } from '@sentry/core';
1+
import { captureException, getCurrentScope, withIsolationScope } from '@sentry/core';
22
import { extractTraceparentData } from '@sentry/utils';
3-
import { TRANSACTION_ATTR_SHOULD_DROP_TRANSACTION } from '../span-attributes-with-logic-attached';
4-
import { escapeNextjsTracing } from '../utils/tracingUtils';
3+
import { dropNextjsRootContext, escapeNextjsTracing } from '../utils/tracingUtils';
54

65
interface FunctionComponent {
76
(...args: unknown[]): unknown;
@@ -26,15 +25,7 @@ export function wrapPageComponentWithSentry(pageComponent: FunctionComponent | C
2625
if (isReactClassComponent(pageComponent)) {
2726
return class SentryWrappedPageComponent extends pageComponent {
2827
public render(...args: unknown[]): unknown {
29-
// Since the spans emitted by Next.js are super buggy with completely wrong timestamps
30-
// (fix pending at the time of writing this: https://github.com/vercel/next.js/pull/70908) we want to intentionally
31-
// drop them. In the future, when Next.js' OTEL instrumentation is in a high-quality place we can potentially think
32-
// about keeping them.
33-
const nextJsOwnedSpan = getActiveSpan();
34-
if (nextJsOwnedSpan) {
35-
getRootSpan(nextJsOwnedSpan)?.setAttribute(TRANSACTION_ATTR_SHOULD_DROP_TRANSACTION, true);
36-
}
37-
28+
dropNextjsRootContext();
3829
return escapeNextjsTracing(() => {
3930
return withIsolationScope(() => {
4031
const scope = getCurrentScope();
@@ -72,15 +63,7 @@ export function wrapPageComponentWithSentry(pageComponent: FunctionComponent | C
7263
} else if (typeof pageComponent === 'function') {
7364
return new Proxy(pageComponent, {
7465
apply(target, thisArg, argArray: [{ _sentryTraceData?: string } | undefined]) {
75-
// Since the spans emitted by Next.js are super buggy with completely wrong timestamps
76-
// (fix pending at the time of writing this: https://github.com/vercel/next.js/pull/70908) we want to intentionally
77-
// drop them. In the future, when Next.js' OTEL instrumentation is in a high-quality place we can potentially think
78-
// about keeping them.
79-
const nextJsOwnedSpan = getActiveSpan();
80-
if (nextJsOwnedSpan) {
81-
getRootSpan(nextJsOwnedSpan)?.setAttribute(TRANSACTION_ATTR_SHOULD_DROP_TRANSACTION, true);
82-
}
83-
66+
dropNextjsRootContext();
8467
return escapeNextjsTracing(() => {
8568
return withIsolationScope(() => {
8669
const scope = getCurrentScope();

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

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ import {
44
SPAN_STATUS_OK,
55
captureException,
66
continueTrace,
7-
getActiveSpan,
8-
getRootSpan,
97
handleCallbackErrors,
108
setHttpStatus,
119
startSpan,
@@ -14,9 +12,8 @@ import {
1412
import { vercelWaitUntil, winterCGRequestToRequestData } from '@sentry/utils';
1513

1614
import type { EdgeRouteHandler } from '../../edge/types';
17-
import { TRANSACTION_ATTR_SHOULD_DROP_TRANSACTION } from '../span-attributes-with-logic-attached';
1815
import { flushSafelyWithTimeout } from './responseEnd';
19-
import { commonObjectToIsolationScope, escapeNextjsTracing } from './tracingUtils';
16+
import { commonObjectToIsolationScope, dropNextjsRootContext, escapeNextjsTracing } from './tracingUtils';
2017

2118
/**
2219
* Wraps a function on the edge runtime with error and performance monitoring.
@@ -26,15 +23,7 @@ export function withEdgeWrapping<H extends EdgeRouteHandler>(
2623
options: { spanDescription: string; spanOp: string; mechanismFunctionName: string },
2724
): (...params: Parameters<H>) => Promise<ReturnType<H>> {
2825
return async function (this: unknown, ...args) {
29-
// Since the spans emitted by Next.js are super buggy with completely wrong timestamps
30-
// (fix pending at the time of writing this: https://github.com/vercel/next.js/pull/70908) we want to intentionally
31-
// drop them. In the future, when Next.js' OTEL instrumentation is in a high-quality place we can potentially think
32-
// about keeping them.
33-
const nextJsOwnedSpan = getActiveSpan();
34-
if (nextJsOwnedSpan) {
35-
getRootSpan(nextJsOwnedSpan)?.setAttribute(TRANSACTION_ATTR_SHOULD_DROP_TRANSACTION, true);
36-
}
37-
26+
dropNextjsRootContext();
3827
return escapeNextjsTracing(() => {
3928
const req: unknown = args[0];
4029
return withIsolationScope(commonObjectToIsolationScope(req), isolationScope => {

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

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { Scope, startNewTrace } from '@sentry/core';
1+
import { Scope, getActiveSpan, getRootSpan, spanToJSON, startNewTrace } from '@sentry/core';
22
import type { PropagationContext } from '@sentry/types';
33
import { GLOBAL_OBJ, logger } from '@sentry/utils';
44
import { DEBUG_BUILD } from '../debug-build';
5+
import { TRANSACTION_ATTR_SHOULD_DROP_TRANSACTION } from '../span-attributes-with-logic-attached';
56

67
const commonPropagationContextMap = new WeakMap<object, PropagationContext>();
78

@@ -92,3 +93,19 @@ export function escapeNextjsTracing<T>(cb: () => T): T {
9293
});
9394
}
9495
}
96+
97+
/**
98+
* Ideally this function never lands in the develop branch.
99+
*
100+
* Drops the entire span tree this function was called in, if it was a span tree created by Next.js.
101+
*/
102+
export function dropNextjsRootContext(): void {
103+
const nextJsOwnedSpan = getActiveSpan();
104+
if (nextJsOwnedSpan) {
105+
const rootSpan = getRootSpan(nextJsOwnedSpan);
106+
const rootSpanAttributes = spanToJSON(rootSpan).data;
107+
if (rootSpanAttributes?.['next.span_type']) {
108+
getRootSpan(nextJsOwnedSpan)?.setAttribute(TRANSACTION_ATTR_SHOULD_DROP_TRANSACTION, true);
109+
}
110+
}
111+
}

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

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ import {
66
SPAN_STATUS_OK,
77
captureException,
88
continueTrace,
9-
getActiveSpan,
10-
getRootSpan,
119
getTraceData,
1210
startInactiveSpan,
1311
startSpan,
@@ -18,9 +16,8 @@ import {
1816
import type { Span } from '@sentry/types';
1917
import { isString, vercelWaitUntil } from '@sentry/utils';
2018

21-
import { TRANSACTION_ATTR_SHOULD_DROP_TRANSACTION } from '../span-attributes-with-logic-attached';
2219
import { autoEndSpanOnResponseEnd, flushSafelyWithTimeout } from './responseEnd';
23-
import { commonObjectToIsolationScope, escapeNextjsTracing } from './tracingUtils';
20+
import { commonObjectToIsolationScope, dropNextjsRootContext, escapeNextjsTracing } from './tracingUtils';
2421

2522
declare module 'http' {
2623
interface IncomingMessage {
@@ -96,15 +93,7 @@ export function withTracedServerSideDataFetcher<F extends (...args: any[]) => Pr
9693
this: unknown,
9794
...args: Parameters<F>
9895
): Promise<{ data: ReturnType<F>; sentryTrace?: string; baggage?: string }> {
99-
// Since the spans emitted by Next.js are super buggy with completely wrong timestamps
100-
// (fix pending at the time of writing this: https://github.com/vercel/next.js/pull/70908) we want to intentionally
101-
// drop them. In the future, when Next.js' OTEL instrumentation is in a high-quality place we can potentially think
102-
// about keeping them.
103-
const nextJsOwnedSpan = getActiveSpan();
104-
if (nextJsOwnedSpan) {
105-
getRootSpan(nextJsOwnedSpan)?.setAttribute(TRANSACTION_ATTR_SHOULD_DROP_TRANSACTION, true);
106-
}
107-
96+
dropNextjsRootContext();
10897
return escapeNextjsTracing(() => {
10998
const isolationScope = commonObjectToIsolationScope(req);
11099
return withIsolationScope(isolationScope, () => {

packages/nextjs/src/common/withServerActionInstrumentation.ts

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
import {
22
SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
33
SPAN_STATUS_ERROR,
4-
getActiveSpan,
4+
captureException,
5+
continueTrace,
6+
getClient,
57
getIsolationScope,
6-
getRootSpan,
8+
handleCallbackErrors,
9+
startSpan,
710
withIsolationScope,
811
} from '@sentry/core';
9-
import { captureException, continueTrace, getClient, handleCallbackErrors, startSpan } from '@sentry/core';
1012
import { logger, vercelWaitUntil } from '@sentry/utils';
1113

1214
import { DEBUG_BUILD } from './debug-build';
1315
import { isNotFoundNavigationError, isRedirectNavigationError } from './nextNavigationErrorUtils';
14-
import { TRANSACTION_ATTR_SHOULD_DROP_TRANSACTION } from './span-attributes-with-logic-attached';
1516
import { flushSafelyWithTimeout } from './utils/responseEnd';
16-
import { escapeNextjsTracing } from './utils/tracingUtils';
17+
import { dropNextjsRootContext, escapeNextjsTracing } from './utils/tracingUtils';
1718

1819
interface Options {
1920
formData?: FormData;
@@ -67,15 +68,7 @@ async function withServerActionInstrumentationImplementation<A extends (...args:
6768
options: Options,
6869
callback: A,
6970
): Promise<ReturnType<A>> {
70-
// Since the spans emitted by Next.js are super buggy with completely wrong timestamps
71-
// (fix pending at the time of writing this: https://github.com/vercel/next.js/pull/70908) we want to intentionally
72-
// drop them. In the future, when Next.js' OTEL instrumentation is in a high-quality place we can potentially think
73-
// about keeping them.
74-
const nextJsOwnedSpan = getActiveSpan();
75-
if (nextJsOwnedSpan) {
76-
getRootSpan(nextJsOwnedSpan)?.setAttribute(TRANSACTION_ATTR_SHOULD_DROP_TRANSACTION, true);
77-
}
78-
71+
dropNextjsRootContext();
7972
return escapeNextjsTracing(() => {
8073
return withIsolationScope(async isolationScope => {
8174
const sendDefaultPii = getClient()?.getOptions().sendDefaultPii;

0 commit comments

Comments
 (0)