Skip to content

Commit 7d43873

Browse files
authored
fix(nextjs): Disable NextJS perf monitoring when using otel (#6820)
1 parent 952d866 commit 7d43873

9 files changed

+40
-15
lines changed

packages/nextjs/src/server/wrapApiHandlerWithSentry.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,14 @@ export function withSentry(origHandler: NextApiHandler, parameterizedRoute?: str
8787
// eslint-disable-next-line complexity
8888
const boundHandler = local.bind(async () => {
8989
let transaction: Transaction | undefined;
90-
const currentScope = getCurrentHub().getScope();
90+
const hub = getCurrentHub();
91+
const currentScope = hub.getScope();
92+
const options = hub.getClient()?.getOptions();
9193

9294
if (currentScope) {
9395
currentScope.setSDKProcessingMetadata({ request: req });
9496

95-
if (hasTracingEnabled()) {
97+
if (hasTracingEnabled(options) && options?.instrumenter === 'sentry') {
9698
// If there is a trace header set, extract the data from it (parentSpanId, traceId, and sampling decision)
9799
let traceparentData;
98100
if (req.headers && isString(req.headers['sentry-trace'])) {
@@ -137,7 +139,6 @@ export function withSentry(origHandler: NextApiHandler, parameterizedRoute?: str
137139
{ request: req },
138140
);
139141
currentScope.setSpan(transaction);
140-
141142
if (platformSupportsStreaming() && !origHandler.__sentry_test_doesnt_support_streaming__) {
142143
autoEndTransactionOnResponseEnd(transaction, res);
143144
} else {

packages/nextjs/src/server/wrapAppGetInitialPropsWithSentry.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { getCurrentHub } from '@sentry/node';
12
import { hasTracingEnabled } from '@sentry/tracing';
23
import { dynamicSamplingContextToSentryBaggageHeader } from '@sentry/utils';
34
import type App from 'next/app';
@@ -29,12 +30,13 @@ export function wrapAppGetInitialPropsWithSentry(origAppGetInitialProps: AppGetI
2930
const { req, res } = context.ctx;
3031

3132
const errorWrappedAppGetInitialProps = withErrorInstrumentation(origAppGetInitialProps);
33+
const options = getCurrentHub().getClient()?.getOptions();
3234

3335
// Generally we can assume that `req` and `res` are always defined on the server:
3436
// https://nextjs.org/docs/api-reference/data-fetching/get-initial-props#context-object
3537
// This does not seem to be the case in dev mode. Because we have no clean way of associating the the data fetcher
3638
// span with each other when there are no req or res objects, we simply do not trace them at all here.
37-
if (hasTracingEnabled() && req && res) {
39+
if (hasTracingEnabled() && req && res && options?.instrumenter === 'sentry') {
3840
const tracedGetInitialProps = withTracedServerSideDataFetcher(errorWrappedAppGetInitialProps, req, res, {
3941
dataFetcherRouteName: '/_app',
4042
requestedRouteName: context.ctx.pathname,

packages/nextjs/src/server/wrapDocumentGetInitialPropsWithSentry.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { getCurrentHub } from '@sentry/node';
12
import { hasTracingEnabled } from '@sentry/tracing';
23
import type Document from 'next/document';
34

@@ -29,12 +30,13 @@ export function wrapDocumentGetInitialPropsWithSentry(
2930
const { req, res } = context;
3031

3132
const errorWrappedGetInitialProps = withErrorInstrumentation(origDocumentGetInitialProps);
33+
const options = getCurrentHub().getClient()?.getOptions();
3234

3335
// Generally we can assume that `req` and `res` are always defined on the server:
3436
// https://nextjs.org/docs/api-reference/data-fetching/get-initial-props#context-object
3537
// This does not seem to be the case in dev mode. Because we have no clean way of associating the the data fetcher
3638
// span with each other when there are no req or res objects, we simply do not trace them at all here.
37-
if (hasTracingEnabled() && req && res) {
39+
if (hasTracingEnabled() && req && res && options?.instrumenter === 'sentry') {
3840
const tracedGetInitialProps = withTracedServerSideDataFetcher(errorWrappedGetInitialProps, req, res, {
3941
dataFetcherRouteName: '/_document',
4042
requestedRouteName: context.pathname,

packages/nextjs/src/server/wrapErrorGetInitialPropsWithSentry.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { getCurrentHub } from '@sentry/node';
12
import { hasTracingEnabled } from '@sentry/tracing';
23
import { dynamicSamplingContextToSentryBaggageHeader } from '@sentry/utils';
34
import type { NextPageContext } from 'next';
@@ -32,12 +33,13 @@ export function wrapErrorGetInitialPropsWithSentry(
3233
const { req, res } = context;
3334

3435
const errorWrappedGetInitialProps = withErrorInstrumentation(origErrorGetInitialProps);
36+
const options = getCurrentHub().getClient()?.getOptions();
3537

3638
// Generally we can assume that `req` and `res` are always defined on the server:
3739
// https://nextjs.org/docs/api-reference/data-fetching/get-initial-props#context-object
3840
// This does not seem to be the case in dev mode. Because we have no clean way of associating the the data fetcher
3941
// span with each other when there are no req or res objects, we simply do not trace them at all here.
40-
if (hasTracingEnabled() && req && res) {
42+
if (hasTracingEnabled() && req && res && options?.instrumenter === 'sentry') {
4143
const tracedGetInitialProps = withTracedServerSideDataFetcher(errorWrappedGetInitialProps, req, res, {
4244
dataFetcherRouteName: '/_error',
4345
requestedRouteName: context.pathname,

packages/nextjs/src/server/wrapGetInitialPropsWithSentry.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { getCurrentHub } from '@sentry/node';
12
import { hasTracingEnabled } from '@sentry/tracing';
23
import { dynamicSamplingContextToSentryBaggageHeader } from '@sentry/utils';
34
import type { NextPage } from 'next';
@@ -28,12 +29,13 @@ export function wrapGetInitialPropsWithSentry(origGetInitialProps: GetInitialPro
2829
const { req, res } = context;
2930

3031
const errorWrappedGetInitialProps = withErrorInstrumentation(origGetInitialProps);
32+
const options = getCurrentHub().getClient()?.getOptions();
3133

3234
// Generally we can assume that `req` and `res` are always defined on the server:
3335
// https://nextjs.org/docs/api-reference/data-fetching/get-initial-props#context-object
3436
// This does not seem to be the case in dev mode. Because we have no clean way of associating the the data fetcher
3537
// span with each other when there are no req or res objects, we simply do not trace them at all here.
36-
if (hasTracingEnabled() && req && res) {
38+
if (hasTracingEnabled() && req && res && options?.instrumenter === 'sentry') {
3739
const tracedGetInitialProps = withTracedServerSideDataFetcher(errorWrappedGetInitialProps, req, res, {
3840
dataFetcherRouteName: context.pathname,
3941
requestedRouteName: context.pathname,

packages/nextjs/src/server/wrapGetServerSidePropsWithSentry.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { getCurrentHub } from '@sentry/node';
12
import { hasTracingEnabled } from '@sentry/tracing';
23
import { dynamicSamplingContextToSentryBaggageHeader } from '@sentry/utils';
34
import type { GetServerSideProps } from 'next';
@@ -29,8 +30,9 @@ export function wrapGetServerSidePropsWithSentry(
2930
const { req, res } = context;
3031

3132
const errorWrappedGetServerSideProps = withErrorInstrumentation(origGetServerSideProps);
33+
const options = getCurrentHub().getClient()?.getOptions();
3234

33-
if (hasTracingEnabled()) {
35+
if (hasTracingEnabled() && options?.instrumenter === 'sentry') {
3436
const tracedGetServerSideProps = withTracedServerSideDataFetcher(errorWrappedGetServerSideProps, req, res, {
3537
dataFetcherRouteName: parameterizedRoute,
3638
requestedRouteName: parameterizedRoute,

packages/nextjs/src/server/wrapGetStaticPropsWithSentry.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { getCurrentHub } from '@sentry/node';
2+
import { hasTracingEnabled } from '@sentry/tracing';
13
import type { GetStaticProps } from 'next';
24

35
import { isBuild } from './utils/isBuild';
@@ -24,11 +26,16 @@ export function wrapGetStaticPropsWithSentry(
2426
}
2527

2628
const errorWrappedGetStaticProps = withErrorInstrumentation(origGetStaticProps);
29+
const options = getCurrentHub().getClient()?.getOptions();
2730

28-
return callDataFetcherTraced(errorWrappedGetStaticProps, getStaticPropsArguments, {
29-
parameterizedRoute,
30-
dataFetchingMethodName: 'getStaticProps',
31-
});
31+
if (hasTracingEnabled() && options?.instrumenter === 'sentry') {
32+
return callDataFetcherTraced(errorWrappedGetStaticProps, getStaticPropsArguments, {
33+
parameterizedRoute,
34+
dataFetchingMethodName: 'getStaticProps',
35+
});
36+
}
37+
38+
return errorWrappedGetStaticProps(...getStaticPropsArguments);
3239
};
3340
}
3441

packages/nextjs/test/config/withSentry.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,9 @@ describe('withSentry', () => {
6666

6767
describe('tracing', () => {
6868
it('starts a transaction and sets metadata when tracing is enabled', async () => {
69-
jest
70-
.spyOn(hub.Hub.prototype, 'getClient')
71-
.mockReturnValueOnce({ getOptions: () => ({ tracesSampleRate: 1 } as ClientOptions) } as Client);
69+
jest.spyOn(hub.Hub.prototype, 'getClient').mockReturnValueOnce({
70+
getOptions: () => ({ tracesSampleRate: 1, instrumenter: 'sentry' } as ClientOptions),
71+
} as Client);
7272

7373
await callWrappedHandler(wrappedHandlerNoError, req, res);
7474

packages/nextjs/test/config/wrappers.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as SentryCore from '@sentry/core';
2+
import * as SentryNode from '@sentry/node';
23
import * as SentryTracing from '@sentry/tracing';
34
import type { IncomingMessage, ServerResponse } from 'http';
45

@@ -17,6 +18,12 @@ describe('data-fetching function wrappers', () => {
1718
res = { end: jest.fn() } as unknown as ServerResponse;
1819

1920
jest.spyOn(SentryTracing, 'hasTracingEnabled').mockReturnValueOnce(true);
21+
jest.spyOn(SentryNode, 'getCurrentHub').mockReturnValueOnce({
22+
getClient: () =>
23+
({
24+
getOptions: () => ({ instrumenter: 'sentry' }),
25+
} as any),
26+
} as any);
2027
});
2128

2229
afterEach(() => {

0 commit comments

Comments
 (0)