Skip to content

Commit

Permalink
add span creation and transaction name replacement to wrapper core fu…
Browse files Browse the repository at this point in the history
…nction
  • Loading branch information
lobsterkatie committed Aug 12, 2022
1 parent f6ff082 commit be3a2fa
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 19 deletions.
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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<GSSP['result']> {
return callOriginal<GSSP>(origGetServerSideProps, context);
return wrapperCore<GSSP>({ origFunction: origGetServerSideProps, context, route, op: 'getServerSideProps' });
};
}
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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<GSProps['result']> {
return callOriginal<GSProps>(origGetStaticProps, context);
return wrapperCore<GSProps>({ origFunction: origGetStaticProps, context, route, op: 'getStaticProps' });
};
}
51 changes: 36 additions & 15 deletions packages/nextjs/src/config/wrappers/wrapperUtils.ts
Original file line number Diff line number Diff line change
@@ -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<T extends DataFetchingFunction>(
origFunction: T['fn'],
context: T['context'],
): Promise<T['result']> {
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<T extends DataFetchingFunction>(options: {
origFunction: T['fn'];
context: T['context'];
route: string;
op: string;
}): Promise<T['result']> {
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);
}

0 comments on commit be3a2fa

Please sign in to comment.