diff --git a/packages/core/src/currentScopes.ts b/packages/core/src/currentScopes.ts index 07e26d9a96b6..1e68c9583372 100644 --- a/packages/core/src/currentScopes.ts +++ b/packages/core/src/currentScopes.ts @@ -1,15 +1,10 @@ import type { Scope } from '@sentry/types'; import type { Client } from '@sentry/types'; +import { getGlobalSingleton } from '@sentry/utils'; import { getMainCarrier } from './asyncContext'; import { getAsyncContextStrategy } from './hub'; import { Scope as ScopeClass } from './scope'; -/** - * The global scope is kept in this module. - * When accessing it, we'll make sure to set one if none is currently present. - */ -let globalScope: Scope | undefined; - /** * Get the currently active scope. */ @@ -34,20 +29,7 @@ export function getIsolationScope(): Scope { * This scope is applied to _all_ events. */ export function getGlobalScope(): Scope { - if (!globalScope) { - globalScope = new ScopeClass(); - } - - return globalScope; -} - -/** - * This is mainly needed for tests. - * DO NOT USE this, as this is an internal API and subject to change. - * @hidden - */ -export function setGlobalScope(scope: Scope | undefined): void { - globalScope = scope; + return getGlobalSingleton('globalScope', () => new ScopeClass()); } /** diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 52841ee68a6d..3fe4d4b3a59a 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -43,7 +43,6 @@ export { getCurrentScope, getIsolationScope, getGlobalScope, - setGlobalScope, withScope, withIsolationScope, getClient, diff --git a/packages/core/src/metrics/exports.ts b/packages/core/src/metrics/exports.ts index c946f3780f8b..2ed0d9cb9d51 100644 --- a/packages/core/src/metrics/exports.ts +++ b/packages/core/src/metrics/exports.ts @@ -4,7 +4,7 @@ import type { MetricsAggregator as MetricsAggregatorInterface, Primitive, } from '@sentry/types'; -import { logger } from '@sentry/utils'; +import { getGlobalSingleton, logger } from '@sentry/utils'; import { getCurrentScope } from '../currentScopes'; import { getClient } from '../currentScopes'; import { DEBUG_BUILD } from '../debug-build'; @@ -23,11 +23,6 @@ type MetricsAggregatorConstructor = { new (client: Client): MetricsAggregatorInterface; }; -/** - * A metrics aggregator instance per Client. - */ -let globalMetricsAggregators: WeakMap | undefined; - /** * Gets the metrics aggregator for a given client. * @param client The client for which to get the metrics aggregator. @@ -37,9 +32,10 @@ function getMetricsAggregatorForClient( client: Client, Aggregator: MetricsAggregatorConstructor, ): MetricsAggregatorInterface { - if (!globalMetricsAggregators) { - globalMetricsAggregators = new WeakMap(); - } + const globalMetricsAggregators = getGlobalSingleton>( + 'globalMetricsAggregators', + () => new WeakMap(), + ); const aggregator = globalMetricsAggregators.get(client); if (aggregator) { diff --git a/packages/core/test/lib/base.test.ts b/packages/core/test/lib/base.test.ts index 8f3af775f095..6c7c8aa0d63d 100644 --- a/packages/core/test/lib/base.test.ts +++ b/packages/core/test/lib/base.test.ts @@ -1,19 +1,12 @@ import type { Client, Envelope, Event } from '@sentry/types'; import { SentryError, SyncPromise, dsnToString, logger } from '@sentry/utils'; -import { - Scope, - addBreadcrumb, - getCurrentScope, - getIsolationScope, - makeSession, - setCurrentClient, - setGlobalScope, -} from '../../src'; +import { Scope, addBreadcrumb, getCurrentScope, getIsolationScope, makeSession, setCurrentClient } from '../../src'; import * as integrationModule from '../../src/integration'; import { TestClient, getDefaultTestClientOptions } from '../mocks/client'; import { AdHocIntegration, TestIntegration } from '../mocks/integration'; import { makeFakeTransport } from '../mocks/transport'; +import { clearGlobalScope } from './clear-global-scope'; const PUBLIC_DSN = 'https://username@domain/123'; // eslint-disable-next-line no-var @@ -62,7 +55,7 @@ describe('BaseClient', () => { beforeEach(() => { TestClient.sendEventCalled = undefined; TestClient.instance = undefined; - setGlobalScope(undefined); + clearGlobalScope(); getCurrentScope().clear(); getCurrentScope().setClient(undefined); getIsolationScope().clear(); diff --git a/packages/core/test/lib/clear-global-scope.ts b/packages/core/test/lib/clear-global-scope.ts new file mode 100644 index 000000000000..5290a610e961 --- /dev/null +++ b/packages/core/test/lib/clear-global-scope.ts @@ -0,0 +1,6 @@ +import { GLOBAL_OBJ } from '@sentry/utils'; + +export function clearGlobalScope() { + const __SENTRY__ = (GLOBAL_OBJ.__SENTRY__ = GLOBAL_OBJ.__SENTRY__ || {}); + __SENTRY__.globalScope = undefined; +} diff --git a/packages/core/test/lib/prepareEvent.test.ts b/packages/core/test/lib/prepareEvent.test.ts index 1ad80fb5ce68..49dcc349f2ed 100644 --- a/packages/core/test/lib/prepareEvent.test.ts +++ b/packages/core/test/lib/prepareEvent.test.ts @@ -9,7 +9,7 @@ import type { ScopeContext, } from '@sentry/types'; import { GLOBAL_OBJ, createStackParser } from '@sentry/utils'; -import { getGlobalScope, getIsolationScope, setGlobalScope } from '../../src'; +import { getGlobalScope, getIsolationScope } from '../../src'; import { Scope } from '../../src/scope'; import { @@ -18,6 +18,7 @@ import { parseEventHintOrCaptureContext, prepareEvent, } from '../../src/utils/prepareEvent'; +import { clearGlobalScope } from './clear-global-scope'; describe('applyDebugIds', () => { afterEach(() => { @@ -191,7 +192,7 @@ describe('parseEventHintOrCaptureContext', () => { describe('prepareEvent', () => { beforeEach(() => { - setGlobalScope(undefined); + clearGlobalScope(); getIsolationScope().clear(); }); diff --git a/packages/core/test/lib/scope.test.ts b/packages/core/test/lib/scope.test.ts index 9dee993efd33..978ebde52c9f 100644 --- a/packages/core/test/lib/scope.test.ts +++ b/packages/core/test/lib/scope.test.ts @@ -4,16 +4,16 @@ import { getCurrentScope, getGlobalScope, getIsolationScope, - setGlobalScope, withIsolationScope, } from '../../src'; import { Scope } from '../../src/scope'; import { TestClient, getDefaultTestClientOptions } from '../mocks/client'; +import { clearGlobalScope } from './clear-global-scope'; describe('Scope', () => { beforeEach(() => { - setGlobalScope(undefined); + clearGlobalScope(); }); it('allows to create & update a scope', () => { @@ -491,7 +491,7 @@ describe('Scope', () => { describe('global scope', () => { beforeEach(() => { - setGlobalScope(undefined); + clearGlobalScope(); }); it('works', () => { diff --git a/packages/node-experimental/test/integration/scope.test.ts b/packages/node-experimental/test/integration/scope.test.ts index 19848c4c78fc..cc8ca4d6b383 100644 --- a/packages/node-experimental/test/integration/scope.test.ts +++ b/packages/node-experimental/test/integration/scope.test.ts @@ -1,5 +1,6 @@ -import { getCurrentScope, setGlobalScope } from '@sentry/core'; +import { getCurrentScope } from '@sentry/core'; import { getClient, getSpanScopes } from '@sentry/opentelemetry'; +import { clearGlobalScope } from '../../../core/test/lib/clear-global-scope'; import * as Sentry from '../../src/'; import type { NodeClient } from '../../src/sdk/client'; @@ -246,7 +247,7 @@ describe('Integration | Scope', () => { describe('global scope', () => { beforeEach(() => { - setGlobalScope(undefined); + clearGlobalScope(); }); it('works before calling init', () => { diff --git a/packages/utils/src/worldwide.ts b/packages/utils/src/worldwide.ts index a2fdfb67e14b..35350f67e9cd 100644 --- a/packages/utils/src/worldwide.ts +++ b/packages/utils/src/worldwide.ts @@ -12,7 +12,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import type { Integration } from '@sentry/types'; +import type { Client, Integration, MetricsAggregator, Scope } from '@sentry/types'; import type { SdkSource } from './env'; @@ -54,6 +54,8 @@ export interface InternalGlobal { // eslint-disable-next-line @typescript-eslint/ban-types [key: string]: Function; }; + globalScope: Scope | undefined; + globalMetricsAggregators: WeakMap | undefined; }; /** * Raw module metadata that is injected by bundler plugins.