From ea4ea86e99f125dc81c3c0aa3a216ccaddb188e6 Mon Sep 17 00:00:00 2001 From: s1gr1d Date: Thu, 2 May 2024 12:05:00 +0200 Subject: [PATCH 1/3] set transaction names on scope --- .../wrapGenerationFunctionWithSentry.ts | 87 +++++++++-------- .../src/common/wrapRouteHandlerWithSentry.ts | 95 ++++++++++--------- 2 files changed, 94 insertions(+), 88 deletions(-) diff --git a/packages/nextjs/src/common/wrapGenerationFunctionWithSentry.ts b/packages/nextjs/src/common/wrapGenerationFunctionWithSentry.ts index 5a320ac4556a..92b9ac0ef8bb 100644 --- a/packages/nextjs/src/common/wrapGenerationFunctionWithSentry.ts +++ b/packages/nextjs/src/common/wrapGenerationFunctionWithSentry.ts @@ -8,6 +8,7 @@ import { handleCallbackErrors, startSpanManual, withIsolationScope, + withScope, } from '@sentry/core'; import type { WebFetchHeaders } from '@sentry/types'; import { propagationContextFromHeaders, winterCGHeadersToDict } from '@sentry/utils'; @@ -59,51 +60,53 @@ export function wrapGenerationFunctionWithSentry a const propagationContext = commonObjectToPropagationContext(headers, incomingPropagationContext); return withIsolationScope(isolationScope, () => { - isolationScope.setTransactionName(`${componentType}.${generationFunctionIdentifier} (${componentRoute})`); - isolationScope.setSDKProcessingMetadata({ - request: { - headers: headers ? winterCGHeadersToDict(headers) : undefined, - }, - }); + return withScope(scope => { + scope.setTransactionName(`${componentType}.${generationFunctionIdentifier} (${componentRoute})`); + isolationScope.setSDKProcessingMetadata({ + request: { + headers: headers ? winterCGHeadersToDict(headers) : undefined, + }, + }); - getCurrentScope().setExtra('route_data', data); - getCurrentScope().setPropagationContext(propagationContext); + getCurrentScope().setExtra('route_data', data); + getCurrentScope().setPropagationContext(propagationContext); - return startSpanManual( - { - op: 'function.nextjs', - name: `${componentType}.${generationFunctionIdentifier} (${componentRoute})`, - forceTransaction: true, - attributes: { - [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.nextjs', - }, - }, - span => { - return handleCallbackErrors( - () => originalFunction.apply(thisArg, args), - err => { - if (isNotFoundNavigationError(err)) { - // We don't want to report "not-found"s - span.setStatus({ code: SPAN_STATUS_ERROR, message: 'not_found' }); - } else if (isRedirectNavigationError(err)) { - // We don't want to report redirects - span.setStatus({ code: SPAN_STATUS_OK }); - } else { - span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' }); - captureException(err, { - mechanism: { - handled: false, - }, - }); - } - }, - () => { - span.end(); + return startSpanManual( + { + op: 'function.nextjs', + name: `${componentType}.${generationFunctionIdentifier} (${componentRoute})`, + forceTransaction: true, + attributes: { + [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route', + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.nextjs', }, - ); - }, - ); + }, + span => { + return handleCallbackErrors( + () => originalFunction.apply(thisArg, args), + err => { + if (isNotFoundNavigationError(err)) { + // We don't want to report "not-found"s + span.setStatus({ code: SPAN_STATUS_ERROR, message: 'not_found' }); + } else if (isRedirectNavigationError(err)) { + // We don't want to report redirects + span.setStatus({ code: SPAN_STATUS_OK }); + } else { + span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' }); + captureException(err, { + mechanism: { + handled: false, + }, + }); + } + }, + () => { + span.end(); + }, + ); + }, + ); + }); }); }); }, diff --git a/packages/nextjs/src/common/wrapRouteHandlerWithSentry.ts b/packages/nextjs/src/common/wrapRouteHandlerWithSentry.ts index b5da2743d97d..1772cd073d60 100644 --- a/packages/nextjs/src/common/wrapRouteHandlerWithSentry.ts +++ b/packages/nextjs/src/common/wrapRouteHandlerWithSentry.ts @@ -9,6 +9,7 @@ import { setHttpStatus, startSpan, withIsolationScope, + withScope, } from '@sentry/core'; import { propagationContextFromHeaders, winterCGHeadersToDict } from '@sentry/utils'; import { isNotFoundNavigationError, isRedirectNavigationError } from './nextNavigationErrorUtils'; @@ -51,57 +52,59 @@ export function wrapRouteHandlerWithSentry any>( const propagationContext = commonObjectToPropagationContext(headers, incomingPropagationContext); - return withIsolationScope(isolationScope, async () => { - isolationScope.setTransactionName(`${method} ${parameterizedRoute}`); - getCurrentScope().setPropagationContext(propagationContext); - try { - return startSpan( - { - name: `${method} ${parameterizedRoute}`, - attributes: { - [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route', - [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.server', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.nextjs', - }, - forceTransaction: true, - }, - async span => { - const response: Response = await handleCallbackErrors( - () => originalFunction.apply(thisArg, args), - error => { - // Next.js throws errors when calling `redirect()`. We don't wanna report these. - if (isRedirectNavigationError(error)) { - // Don't do anything - } else if (isNotFoundNavigationError(error) && span) { - span.setStatus({ code: SPAN_STATUS_ERROR, message: 'not_found' }); - } else { - captureException(error, { - mechanism: { - handled: false, - }, - }); - } + return withIsolationScope(isolationScope, () => { + return withScope(async () => { + isolationScope.setTransactionName(`${method} ${parameterizedRoute}`); + getCurrentScope().setPropagationContext(propagationContext); + try { + return startSpan( + { + name: `${method} ${parameterizedRoute}`, + attributes: { + [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route', + [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.server', + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.nextjs', }, - ); + forceTransaction: true, + }, + async span => { + const response: Response = await handleCallbackErrors( + () => originalFunction.apply(thisArg, args), + error => { + // Next.js throws errors when calling `redirect()`. We don't wanna report these. + if (isRedirectNavigationError(error)) { + // Don't do anything + } else if (isNotFoundNavigationError(error) && span) { + span.setStatus({ code: SPAN_STATUS_ERROR, message: 'not_found' }); + } else { + captureException(error, { + mechanism: { + handled: false, + }, + }); + } + }, + ); - try { - if (span && response.status) { - setHttpStatus(span, response.status); + try { + if (span && response.status) { + setHttpStatus(span, response.status); + } + } catch { + // best effort - response may be undefined? } - } catch { - // best effort - response may be undefined? - } - return response; - }, - ); - } finally { - if (!platformSupportsStreaming() || process.env.NEXT_RUNTIME === 'edge') { - // 1. Edge transport requires manual flushing - // 2. Lambdas require manual flushing to prevent execution freeze before the event is sent - await flushQueue(); + return response; + }, + ); + } finally { + if (!platformSupportsStreaming() || process.env.NEXT_RUNTIME === 'edge') { + // 1. Edge transport requires manual flushing + // 2. Lambdas require manual flushing to prevent execution freeze before the event is sent + await flushQueue(); + } } - } + }); }); }); }, From af5c5b2ca32f88084cefbf48c2abb98449571246 Mon Sep 17 00:00:00 2001 From: s1gr1d Date: Thu, 2 May 2024 13:47:00 +0200 Subject: [PATCH 2/3] use scope instead getCurrentScope() --- .../nextjs/src/common/wrapGenerationFunctionWithSentry.ts | 5 ++--- packages/nextjs/src/common/wrapRouteHandlerWithSentry.ts | 7 +++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/nextjs/src/common/wrapGenerationFunctionWithSentry.ts b/packages/nextjs/src/common/wrapGenerationFunctionWithSentry.ts index 92b9ac0ef8bb..f3998b693b38 100644 --- a/packages/nextjs/src/common/wrapGenerationFunctionWithSentry.ts +++ b/packages/nextjs/src/common/wrapGenerationFunctionWithSentry.ts @@ -4,7 +4,6 @@ import { SPAN_STATUS_OK, captureException, getClient, - getCurrentScope, handleCallbackErrors, startSpanManual, withIsolationScope, @@ -68,8 +67,8 @@ export function wrapGenerationFunctionWithSentry a }, }); - getCurrentScope().setExtra('route_data', data); - getCurrentScope().setPropagationContext(propagationContext); + scope.setExtra('route_data', data); + scope.setPropagationContext(propagationContext); return startSpanManual( { diff --git a/packages/nextjs/src/common/wrapRouteHandlerWithSentry.ts b/packages/nextjs/src/common/wrapRouteHandlerWithSentry.ts index 1772cd073d60..7e1965be73d5 100644 --- a/packages/nextjs/src/common/wrapRouteHandlerWithSentry.ts +++ b/packages/nextjs/src/common/wrapRouteHandlerWithSentry.ts @@ -4,7 +4,6 @@ import { SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, SPAN_STATUS_ERROR, captureException, - getCurrentScope, handleCallbackErrors, setHttpStatus, startSpan, @@ -53,9 +52,9 @@ export function wrapRouteHandlerWithSentry any>( const propagationContext = commonObjectToPropagationContext(headers, incomingPropagationContext); return withIsolationScope(isolationScope, () => { - return withScope(async () => { - isolationScope.setTransactionName(`${method} ${parameterizedRoute}`); - getCurrentScope().setPropagationContext(propagationContext); + return withScope(async (scope) => { + scope.setTransactionName(`${method} ${parameterizedRoute}`); + scope.setPropagationContext(propagationContext); try { return startSpan( { From d9205794c9dc622cbd378e47347474f6c570a889 Mon Sep 17 00:00:00 2001 From: s1gr1d Date: Thu, 2 May 2024 14:09:37 +0200 Subject: [PATCH 3/3] fix formatting --- packages/nextjs/src/common/wrapRouteHandlerWithSentry.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nextjs/src/common/wrapRouteHandlerWithSentry.ts b/packages/nextjs/src/common/wrapRouteHandlerWithSentry.ts index 7e1965be73d5..be378dc8cd5e 100644 --- a/packages/nextjs/src/common/wrapRouteHandlerWithSentry.ts +++ b/packages/nextjs/src/common/wrapRouteHandlerWithSentry.ts @@ -52,7 +52,7 @@ export function wrapRouteHandlerWithSentry any>( const propagationContext = commonObjectToPropagationContext(headers, incomingPropagationContext); return withIsolationScope(isolationScope, () => { - return withScope(async (scope) => { + return withScope(async scope => { scope.setTransactionName(`${method} ${parameterizedRoute}`); scope.setPropagationContext(propagationContext); try {