diff --git a/packages/nextjs/src/config/wrappers/withSentryGetServerSideProps.ts b/packages/nextjs/src/config/wrappers/withSentryGetServerSideProps.ts index bad402023ab3..4e0bd2f69698 100644 --- a/packages/nextjs/src/config/wrappers/withSentryGetServerSideProps.ts +++ b/packages/nextjs/src/config/wrappers/withSentryGetServerSideProps.ts @@ -1,5 +1,5 @@ import { GSSP } from './types'; -import { callOriginal } from './wrapperUtils'; +import { wrapperCore } from './wrapperUtils'; /** * Create a wrapped version of the user's exported `getServerSideProps` function @@ -10,6 +10,6 @@ import { callOriginal } from './wrapperUtils'; */ export function withSentryGetServerSideProps(origGetServerSideProps: GSSP['fn'], route: string): GSSP['wrappedFn'] { return async function (context: GSSP['context']): Promise { - return callOriginal(origGetServerSideProps, context); + return wrapperCore({ origFunction: origGetServerSideProps, context, route, op: 'getServerSideProps' }); }; } diff --git a/packages/nextjs/src/config/wrappers/withSentryGetStaticProps.ts b/packages/nextjs/src/config/wrappers/withSentryGetStaticProps.ts index 88cda4890b86..154d514f936a 100644 --- a/packages/nextjs/src/config/wrappers/withSentryGetStaticProps.ts +++ b/packages/nextjs/src/config/wrappers/withSentryGetStaticProps.ts @@ -1,5 +1,5 @@ import { GSProps } from './types'; -import { callOriginal } from './wrapperUtils'; +import { wrapperCore } from './wrapperUtils'; /** * Create a wrapped version of the user's exported `getStaticProps` function @@ -10,6 +10,6 @@ import { callOriginal } from './wrapperUtils'; */ export function withSentryGetStaticProps(origGetStaticProps: GSProps['fn'], route: string): GSProps['wrappedFn'] { return async function (context: GSProps['context']): Promise { - return callOriginal(origGetStaticProps, context); + return wrapperCore({ origFunction: origGetStaticProps, context, route, op: 'getStaticProps' }); }; } diff --git a/packages/nextjs/src/config/wrappers/wrapperUtils.ts b/packages/nextjs/src/config/wrappers/wrapperUtils.ts index d7a466cb8221..38121ed37b8a 100644 --- a/packages/nextjs/src/config/wrappers/wrapperUtils.ts +++ b/packages/nextjs/src/config/wrappers/wrapperUtils.ts @@ -1,25 +1,46 @@ +import { getActiveTransaction } from '@sentry/tracing'; + import { DataFetchingFunction } from './types'; /** - * Pass-through wrapper for the original function, used as a first step in eventually wrapping the data-fetching - * functions with code for tracing. + * Create a span to track the wrapped function and update transaction name with parameterized route. * * @template T Types for `getInitialProps`, `getStaticProps`, and `getServerSideProps` * @param origFunction The user's exported `getInitialProps`, `getStaticProps`, or `getServerSideProps` function * @param context The context object passed by nextjs to the function * @returns The result of calling the user's function */ -export async function callOriginal( - origFunction: T['fn'], - context: T['context'], -): Promise { - let props; - - // TODO: Can't figure out how to tell TS that the types are correlated - that a `GSPropsFunction` will only get passed - // `GSPropsContext` and never, say, `GSSPContext`. That's what wrapping everything in objects and using the generic - // and pulling the types from the generic rather than specifying them directly was supposed to do, but... no luck. - // eslint-disable-next-line prefer-const, @typescript-eslint/no-explicit-any - props = await (origFunction as any)(context); - - return props; +export async function wrapperCore(options: { + origFunction: T['fn']; + context: T['context']; + route: string; + op: string; +}): Promise { + const { origFunction, context, route, op } = options; + + const transaction = getActiveTransaction(); + + if (transaction) { + // TODO: Make sure that the given route matches the name of the active transaction (to prevent background data + // fetching from switching the name to a completely other route) + transaction.name = route; + transaction.metadata.source = 'route'; + + // Capture the route, since pre-loading, revalidation, etc might mean that this span may happen during another + // route's transaction + const span = transaction.startChild({ op, data: { route } }); + + // TODO: Can't figure out how to tell TS that the types are correlated - that a `GSPropsFunction` will only get passed + // `GSPropsContext` and never, say, `GSSPContext`. That's what wrapping everything in objects and using the generic + // and pulling the types from the generic rather than specifying them directly was supposed to do, but... no luck. + // eslint-disable-next-line prefer-const, @typescript-eslint/no-explicit-any + const props = await (origFunction as any)(context); + + span.finish(); + + return props; + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return (origFunction as any)(context); }