Skip to content

Commit 46a527b

Browse files
authored
feat(tracing): Add enableTracing option (#7238)
1 parent c5c223c commit 46a527b

34 files changed

+203
-68
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
- "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott
66

7+
This release adds a new `enableTracing` option, which can be used instead of `tracesSampleRate` for an easier setup.
8+
Related to this, the `hasTracingEnabled` utility function was moved from `@sentry/tracing` to `@sentry/core`.
9+
The old export from `@sentry/tracing` has been deprecated and will be removed in v8.
10+
711
## 7.37.2
812

913
This release includes changes and fixes around text masking and blocking in Replay's `rrweb` dependency. See versions [1.102.0](https://github.com/getsentry/rrweb/releases/tag/1.102.0) and [1.103.0](https://github.com/getsentry/rrweb/releases/tag/1.103.0).

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"lint:eslint": "lerna run lint:eslint",
2626
"postpublish": "lerna run --stream --concurrency 1 postpublish",
2727
"test": "lerna run --ignore @sentry-internal/* test",
28+
"test:unit": "lerna run --ignore @sentry-internal/* test:unit",
2829
"test-ci-browser": "lerna run test --ignore \"@sentry/{node,opentelemetry-node,serverless,nextjs,remix,gatsby}\" --ignore @sentry-internal/*",
2930
"test-ci-node": "ts-node ./scripts/node-unit-tests.ts",
3031
"test:update-snapshots": "lerna run test:update-snapshots"

packages/core/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export { SDK_VERSION } from './version';
3030
export { getIntegrationsToSetup } from './integration';
3131
export { FunctionToString, InboundFilters } from './integrations';
3232
export { prepareEvent } from './utils/prepareEvent';
33+
export { hasTracingEnabled } from './utils/hasTracingEnabled';
3334

3435
import * as Integrations from './integrations';
3536

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import type { Options } from '@sentry/types';
2+
3+
import { getCurrentHub } from '../hub';
4+
5+
// Treeshakable guard to remove all code related to tracing
6+
declare const __SENTRY_TRACING__: boolean | undefined;
7+
8+
/**
9+
* Determines if tracing is currently enabled.
10+
*
11+
* Tracing is enabled when at least one of `tracesSampleRate` and `tracesSampler` is defined in the SDK config.
12+
*/
13+
export function hasTracingEnabled(
14+
maybeOptions?: Pick<Options, 'tracesSampleRate' | 'tracesSampler' | 'enableTracing'> | undefined,
15+
): boolean {
16+
if (typeof __SENTRY_TRACING__ === 'boolean' && !__SENTRY_TRACING__) {
17+
return false;
18+
}
19+
20+
const client = getCurrentHub().getClient();
21+
const options = maybeOptions || (client && client.getOptions());
22+
return !!options && (options.enableTracing || 'tracesSampleRate' in options || 'tracesSampler' in options);
23+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { hasTracingEnabled } from '../../../src';
2+
3+
describe('hasTracingEnabled', () => {
4+
const tracesSampler = () => 1;
5+
const tracesSampleRate = 1;
6+
it.each([
7+
['No options', undefined, false],
8+
['No tracesSampler or tracesSampleRate or enableTracing', {}, false],
9+
['With tracesSampler', { tracesSampler }, true],
10+
['With tracesSampleRate', { tracesSampleRate }, true],
11+
['With enableTracing=true', { enableTracing: true }, true],
12+
['With enableTracing=false', { enableTracing: false }, false],
13+
['With tracesSampler && enableTracing=false', { tracesSampler, enableTracing: false }, true],
14+
['With tracesSampleRate && enableTracing=false', { tracesSampler, enableTracing: false }, true],
15+
['With tracesSampler and tracesSampleRate', { tracesSampler, tracesSampleRate }, true],
16+
[
17+
'With tracesSampler and tracesSampleRate and enableTracing=true',
18+
{ tracesSampler, tracesSampleRate, enableTracing: true },
19+
true,
20+
],
21+
[
22+
'With tracesSampler and tracesSampleRate and enableTracing=false',
23+
{ tracesSampler, tracesSampleRate, enableTracing: false },
24+
true,
25+
],
26+
])(
27+
'%s',
28+
(_: string, input: Parameters<typeof hasTracingEnabled>[0], output: ReturnType<typeof hasTracingEnabled>) => {
29+
expect(hasTracingEnabled(input)).toBe(output);
30+
},
31+
);
32+
});

packages/gatsby/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"access": "public"
2121
},
2222
"dependencies": {
23+
"@sentry/core": "7.38.0",
2324
"@sentry/react": "7.38.0",
2425
"@sentry/tracing": "7.38.0",
2526
"@sentry/types": "7.38.0",

packages/gatsby/src/utils/integrations.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { hasTracingEnabled } from '@sentry/core';
12
import * as Tracing from '@sentry/tracing';
23
import type { Integration } from '@sentry/types';
34

@@ -13,7 +14,7 @@ export type UserIntegrations = Integration[] | UserFnIntegrations;
1314
* @param options The options users have defined.
1415
*/
1516
export function getIntegrationsFromOptions(options: GatsbyOptions): UserIntegrations {
16-
const isTracingEnabled = Tracing.hasTracingEnabled(options);
17+
const isTracingEnabled = hasTracingEnabled(options);
1718
if (options.integrations === undefined) {
1819
return getIntegrationsFromArray([], isTracingEnabled);
1920
} else if (Array.isArray(options.integrations)) {

packages/nextjs/src/client/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
import { hasTracingEnabled } from '@sentry/core';
12
import { RewriteFrames } from '@sentry/integrations';
23
import type { BrowserOptions } from '@sentry/react';
34
import { configureScope, init as reactInit, Integrations } from '@sentry/react';
4-
import { BrowserTracing, defaultRequestInstrumentationOptions, hasTracingEnabled } from '@sentry/tracing';
5+
import { BrowserTracing, defaultRequestInstrumentationOptions } from '@sentry/tracing';
56
import type { EventProcessor } from '@sentry/types';
67

78
import { getVercelEnv } from '../common/getVercelEnv';

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { captureException, getCurrentHub, startTransaction } from '@sentry/core';
2-
import { hasTracingEnabled } from '@sentry/tracing';
1+
import { captureException, getCurrentHub, hasTracingEnabled, startTransaction } from '@sentry/core';
32
import type { Span } from '@sentry/types';
43
import {
54
addExceptionMechanism,

packages/nextjs/src/server/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import type { Carrier } from '@sentry/core';
2-
import { getHubFromCarrier, getMainCarrier } from '@sentry/core';
2+
import { getHubFromCarrier, getMainCarrier, hasTracingEnabled } from '@sentry/core';
33
import { RewriteFrames } from '@sentry/integrations';
44
import type { NodeOptions } from '@sentry/node';
55
import { configureScope, getCurrentHub, init as nodeInit, Integrations } from '@sentry/node';
6-
import { hasTracingEnabled } from '@sentry/tracing';
76
import type { EventProcessor } from '@sentry/types';
87
import { escapeStringForRegex, logger } from '@sentry/utils';
98
import * as domainModule from 'domain';

packages/nextjs/src/server/wrapApiHandlerWithSentry.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
import { hasTracingEnabled } from '@sentry/core';
12
import { captureException, getCurrentHub, startTransaction } from '@sentry/node';
2-
import { extractTraceparentData, hasTracingEnabled } from '@sentry/tracing';
3+
import { extractTraceparentData } from '@sentry/tracing';
34
import type { Transaction } from '@sentry/types';
45
import {
56
addExceptionMechanism,

packages/nextjs/src/server/wrapAppGetInitialPropsWithSentry.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1+
import { hasTracingEnabled } from '@sentry/core';
12
import { getCurrentHub } from '@sentry/node';
2-
import { hasTracingEnabled } from '@sentry/tracing';
33
import { dynamicSamplingContextToSentryBaggageHeader } from '@sentry/utils';
44
import type App from 'next/app';
55

packages/nextjs/src/server/wrapDocumentGetInitialPropsWithSentry.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1+
import { hasTracingEnabled } from '@sentry/core';
12
import { getCurrentHub } from '@sentry/node';
2-
import { hasTracingEnabled } from '@sentry/tracing';
33
import type Document from 'next/document';
44

55
import { isBuild } from './utils/isBuild';

packages/nextjs/src/server/wrapErrorGetInitialPropsWithSentry.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1+
import { hasTracingEnabled } from '@sentry/core';
12
import { getCurrentHub } from '@sentry/node';
2-
import { hasTracingEnabled } from '@sentry/tracing';
33
import { dynamicSamplingContextToSentryBaggageHeader } from '@sentry/utils';
44
import type { NextPageContext } from 'next';
55
import type { ErrorProps } from 'next/error';

packages/nextjs/src/server/wrapGetInitialPropsWithSentry.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1+
import { hasTracingEnabled } from '@sentry/core';
12
import { getCurrentHub } from '@sentry/node';
2-
import { hasTracingEnabled } from '@sentry/tracing';
33
import { dynamicSamplingContextToSentryBaggageHeader } from '@sentry/utils';
44
import type { NextPage } from 'next';
55

packages/nextjs/src/server/wrapGetServerSidePropsWithSentry.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1+
import { hasTracingEnabled } from '@sentry/core';
12
import { getCurrentHub } from '@sentry/node';
2-
import { hasTracingEnabled } from '@sentry/tracing';
33
import { dynamicSamplingContextToSentryBaggageHeader } from '@sentry/utils';
44
import type { GetServerSideProps } from 'next';
55

packages/nextjs/src/server/wrapGetStaticPropsWithSentry.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1+
import { hasTracingEnabled } from '@sentry/core';
12
import { getCurrentHub } from '@sentry/node';
2-
import { hasTracingEnabled } from '@sentry/tracing';
33
import type { GetStaticProps } from 'next';
44

55
import { isBuild } from './utils/isBuild';

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import * as SentryCore from '@sentry/core';
22
import * as SentryNode from '@sentry/node';
3-
import * as SentryTracing from '@sentry/tracing';
43
import type { IncomingMessage, ServerResponse } from 'http';
54

65
import { wrapGetInitialPropsWithSentry, wrapGetServerSidePropsWithSentry } from '../../src/server';
@@ -17,7 +16,7 @@ describe('data-fetching function wrappers', () => {
1716
req = { headers: {}, url: 'http://dogs.are.great/tricks/kangaroo' } as IncomingMessage;
1817
res = { end: jest.fn() } as unknown as ServerResponse;
1918

20-
jest.spyOn(SentryTracing, 'hasTracingEnabled').mockReturnValueOnce(true);
19+
jest.spyOn(SentryCore, 'hasTracingEnabled').mockReturnValueOnce(true);
2120
jest.spyOn(SentryNode, 'getCurrentHub').mockReturnValueOnce({
2221
getClient: () =>
2322
({

packages/nextjs/test/edge/edgeWrapperUtils.test.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import * as coreSdk from '@sentry/core';
2-
import * as sentryTracing from '@sentry/tracing';
32

43
import { withEdgeWrapping } from '../../src/edge/utils/edgeWrapperUtils';
54

@@ -30,7 +29,7 @@ afterAll(() => {
3029
beforeEach(() => {
3130
jest.clearAllMocks();
3231
jest.resetAllMocks();
33-
jest.spyOn(sentryTracing, 'hasTracingEnabled').mockImplementation(() => true);
32+
jest.spyOn(coreSdk, 'hasTracingEnabled').mockImplementation(() => true);
3433
});
3534

3635
describe('withEdgeWrapping', () => {

packages/nextjs/test/edge/withSentryAPI.test.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import * as coreSdk from '@sentry/core';
2-
import * as sentryTracing from '@sentry/tracing';
32

43
import { wrapApiHandlerWithSentry } from '../../src/edge';
54

@@ -32,7 +31,7 @@ afterAll(() => {
3231
beforeEach(() => {
3332
jest.resetAllMocks();
3433
jest.restoreAllMocks();
35-
jest.spyOn(sentryTracing, 'hasTracingEnabled').mockImplementation(() => true);
34+
jest.spyOn(coreSdk, 'hasTracingEnabled').mockImplementation(() => true);
3635
});
3736

3837
describe('wrapApiHandlerWithSentry', () => {

packages/node/src/handlers.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* eslint-disable @typescript-eslint/no-explicit-any */
2-
import { captureException, getCurrentHub, startTransaction, withScope } from '@sentry/core';
2+
import { captureException, getCurrentHub, hasTracingEnabled, startTransaction, withScope } from '@sentry/core';
33
import type { Span } from '@sentry/types';
44
import type { AddRequestDataToEventOptions } from '@sentry/utils';
55
import {
@@ -46,9 +46,7 @@ export function tracingHandler(): (
4646
return next();
4747
}
4848

49-
// TODO: This is the `hasTracingEnabled` check, but we're doing it manually since `@sentry/tracing` isn't a
50-
// dependency of `@sentry/node`. Long term, that function should probably move to `@sentry/hub.
51-
if (!('tracesSampleRate' in options) && !('tracesSampler' in options)) {
49+
if (!hasTracingEnabled(options)) {
5250
__DEBUG_BUILD__ &&
5351
logger.warn(
5452
'Sentry `tracingHandler` is being used, but tracing is disabled. Please enable tracing by setting ' +

packages/node/test/handlers.test.ts

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import * as sentryCore from '@sentry/core';
2-
import { Hub, makeMain, Scope } from '@sentry/core';
32
import { Transaction } from '@sentry/tracing';
43
import type { Event } from '@sentry/types';
54
import { SentryError } from '@sentry/utils';
@@ -47,7 +46,7 @@ describe('requestHandler', () => {
4746
it('autoSessionTracking is enabled, sets requestSession status to ok, when handling a request', () => {
4847
const options = getDefaultNodeClientOptions({ autoSessionTracking: true, release: '1.2' });
4948
client = new NodeClient(options);
50-
const hub = new Hub(client);
49+
const hub = new sentryCore.Hub(client);
5150

5251
jest.spyOn(sentryCore, 'getCurrentHub').mockReturnValue(hub);
5352

@@ -60,7 +59,7 @@ describe('requestHandler', () => {
6059
it('autoSessionTracking is disabled, does not set requestSession, when handling a request', () => {
6160
const options = getDefaultNodeClientOptions({ autoSessionTracking: false, release: '1.2' });
6261
client = new NodeClient(options);
63-
const hub = new Hub(client);
62+
const hub = new sentryCore.Hub(client);
6463

6564
jest.spyOn(sentryCore, 'getCurrentHub').mockReturnValue(hub);
6665

@@ -73,7 +72,7 @@ describe('requestHandler', () => {
7372
it('autoSessionTracking is enabled, calls _captureRequestSession, on response finish', done => {
7473
const options = getDefaultNodeClientOptions({ autoSessionTracking: true, release: '1.2' });
7574
client = new NodeClient(options);
76-
const hub = new Hub(client);
75+
const hub = new sentryCore.Hub(client);
7776

7877
jest.spyOn(sentryCore, 'getCurrentHub').mockReturnValue(hub);
7978

@@ -94,7 +93,7 @@ describe('requestHandler', () => {
9493
it('autoSessionTracking is disabled, does not call _captureRequestSession, on response finish', done => {
9594
const options = getDefaultNodeClientOptions({ autoSessionTracking: false, release: '1.2' });
9695
client = new NodeClient(options);
97-
const hub = new Hub(client);
96+
const hub = new sentryCore.Hub(client);
9897
jest.spyOn(sentryCore, 'getCurrentHub').mockReturnValue(hub);
9998

10099
const captureRequestSession = jest.spyOn<any, any>(client, '_captureRequestSession');
@@ -138,7 +137,7 @@ describe('requestHandler', () => {
138137
});
139138

140139
it('stores request and request data options in `sdkProcessingMetadata`', () => {
141-
const hub = new Hub(new NodeClient(getDefaultNodeClientOptions()));
140+
const hub = new sentryCore.Hub(new NodeClient(getDefaultNodeClientOptions()));
142141
jest.spyOn(sentryCore, 'getCurrentHub').mockReturnValue(hub);
143142

144143
const requestHandlerOptions = { include: { ip: false } };
@@ -165,15 +164,15 @@ describe('tracingHandler', () => {
165164

166165
const sentryTracingMiddleware = tracingHandler();
167166

168-
let hub: Hub, req: http.IncomingMessage, res: http.ServerResponse, next: () => undefined;
167+
let hub: sentryCore.Hub, req: http.IncomingMessage, res: http.ServerResponse, next: () => undefined;
169168

170169
function createNoOpSpy() {
171170
const noop = { noop: () => undefined }; // this is wrapped in an object so jest can spy on it
172171
return jest.spyOn(noop, 'noop') as any;
173172
}
174173

175174
beforeEach(() => {
176-
hub = new Hub(new NodeClient(getDefaultNodeClientOptions({ tracesSampleRate: 1.0 })));
175+
hub = new sentryCore.Hub(new NodeClient(getDefaultNodeClientOptions({ tracesSampleRate: 1.0 })));
177176
jest.spyOn(sentryCore, 'getCurrentHub').mockReturnValue(hub);
178177
req = {
179178
headers,
@@ -271,7 +270,7 @@ describe('tracingHandler', () => {
271270
it('extracts request data for sampling context', () => {
272271
const tracesSampler = jest.fn();
273272
const options = getDefaultNodeClientOptions({ tracesSampler });
274-
const hub = new Hub(new NodeClient(options));
273+
const hub = new sentryCore.Hub(new NodeClient(options));
275274
hub.run(() => {
276275
sentryTracingMiddleware(req, res, next);
277276

@@ -291,7 +290,7 @@ describe('tracingHandler', () => {
291290

292291
it('puts its transaction on the scope', () => {
293292
const options = getDefaultNodeClientOptions({ tracesSampleRate: 1.0 });
294-
const hub = new Hub(new NodeClient(options));
293+
const hub = new sentryCore.Hub(new NodeClient(options));
295294

296295
jest.spyOn(sentryCore, 'getCurrentHub').mockReturnValue(hub);
297296

@@ -411,7 +410,7 @@ describe('tracingHandler', () => {
411410

412411
it('stores request in transaction metadata', () => {
413412
const options = getDefaultNodeClientOptions({ tracesSampleRate: 1.0 });
414-
const hub = new Hub(new NodeClient(options));
413+
const hub = new sentryCore.Hub(new NodeClient(options));
415414

416415
jest.spyOn(sentryCore, 'getCurrentHub').mockReturnValue(hub);
417416

@@ -465,7 +464,7 @@ describe('errorHandler()', () => {
465464
client.initSessionFlusher();
466465

467466
const scope = sentryCore.getCurrentHub().getScope();
468-
const hub = new Hub(client);
467+
const hub = new sentryCore.Hub(client);
469468

470469
jest.spyOn<any, any>(client, '_captureRequestSession');
471470
jest.spyOn(sentryCore, 'getCurrentHub').mockReturnValue(hub);
@@ -481,7 +480,7 @@ describe('errorHandler()', () => {
481480
client = new NodeClient(options);
482481

483482
const scope = sentryCore.getCurrentHub().getScope();
484-
const hub = new Hub(client);
483+
const hub = new sentryCore.Hub(client);
485484

486485
jest.spyOn<any, any>(client, '_captureRequestSession');
487486
jest.spyOn(sentryCore, 'getCurrentHub').mockReturnValue(hub);
@@ -498,8 +497,8 @@ describe('errorHandler()', () => {
498497
// It is required to initialise SessionFlusher to capture Session Aggregates (it is usually initialised
499498
// by the`requestHandler`)
500499
client.initSessionFlusher();
501-
const scope = new Scope();
502-
const hub = new Hub(client, scope);
500+
const scope = new sentryCore.Scope();
501+
const hub = new sentryCore.Hub(client, scope);
503502

504503
jest.spyOn<any, any>(client, '_captureRequestSession');
505504

@@ -517,8 +516,8 @@ describe('errorHandler()', () => {
517516
// It is required to initialise SessionFlusher to capture Session Aggregates (it is usually initialised
518517
// by the`requestHandler`)
519518
client.initSessionFlusher();
520-
const scope = new Scope();
521-
const hub = new Hub(client, scope);
519+
const scope = new sentryCore.Scope();
520+
const hub = new sentryCore.Hub(client, scope);
522521

523522
jest.spyOn<any, any>(client, '_captureRequestSession');
524523
jest.spyOn(sentryCore, 'getCurrentHub').mockReturnValue(hub);
@@ -532,12 +531,12 @@ describe('errorHandler()', () => {
532531
const options = getDefaultNodeClientOptions({});
533532
client = new NodeClient(options);
534533

535-
const hub = new Hub(client);
536-
makeMain(hub);
534+
const hub = new sentryCore.Hub(client);
535+
sentryCore.makeMain(hub);
537536

538537
// `sentryErrorMiddleware` uses `withScope`, and we need access to the temporary scope it creates, so monkeypatch
539538
// `captureException` in order to examine the scope as it exists inside the `withScope` callback
540-
hub.captureException = function (this: Hub, _exception: any) {
539+
hub.captureException = function (this: sentryCore.Hub, _exception: any) {
541540
const scope = this.getScope();
542541
expect((scope as any)._sdkProcessingMetadata.request).toEqual(req);
543542
} as any;

0 commit comments

Comments
 (0)