diff --git a/packages/astro/src/index.server.ts b/packages/astro/src/index.server.ts index 2eec2fc1e0e9..a7eab7f0fbe9 100644 --- a/packages/astro/src/index.server.ts +++ b/packages/astro/src/index.server.ts @@ -46,6 +46,7 @@ export { // eslint-disable-next-line deprecation/deprecation trace, withScope, + withIsolationScope, autoDiscoverNodePerformanceMonitoringIntegrations, makeNodeTransport, defaultIntegrations, diff --git a/packages/browser/src/exports.ts b/packages/browser/src/exports.ts index f63fe20fdead..f0e167db50b4 100644 --- a/packages/browser/src/exports.ts +++ b/packages/browser/src/exports.ts @@ -60,6 +60,7 @@ export { setTags, setUser, withScope, + withIsolationScope, FunctionToString, InboundFilters, metrics, diff --git a/packages/bun/src/index.ts b/packages/bun/src/index.ts index bb033496da02..83b4b90ab01b 100644 --- a/packages/bun/src/index.ts +++ b/packages/bun/src/index.ts @@ -66,6 +66,7 @@ export { // eslint-disable-next-line deprecation/deprecation trace, withScope, + withIsolationScope, captureCheckIn, withMonitor, setMeasurement, diff --git a/packages/core/src/exports.ts b/packages/core/src/exports.ts index e92114a024dd..001ce3a2aaf1 100644 --- a/packages/core/src/exports.ts +++ b/packages/core/src/exports.ts @@ -25,6 +25,7 @@ import { GLOBAL_OBJ, isThenable, logger, timestampInSeconds, uuid4 } from '@sent import { DEFAULT_ENVIRONMENT } from './constants'; import { DEBUG_BUILD } from './debug-build'; import type { Hub } from './hub'; +import { runWithAsyncContext } from './hub'; import { getCurrentHub, getIsolationScope } from './hub'; import type { Scope } from './scope'; import { closeSession, makeSession, updateSession } from './session'; @@ -35,7 +36,7 @@ import { parseEventHintOrCaptureContext } from './utils/prepareEvent'; * Captures an exception event and sends it to Sentry. * * @param exception The exception to capture. - * @param hint Optinal additional data to attach to the Sentry event. + * @param hint Optional additional data to attach to the Sentry event. * @returns the id of the captured Sentry event. */ export function captureException( @@ -208,6 +209,26 @@ export function withScope( return getCurrentHub().withScope(rest[0]); } +/** + * Attempts to fork the current isolation scope and the current scope based on the current async context strategy. If no + * async context strategy is set, the isolation scope and the current scope will not be forked (this is currently the + * case, for example, in the browser). + * + * Usage of this function in environments without async context strategy is discouraged and may lead to unexpected behaviour. + * + * This function is intended for Sentry SDK and SDK integration development. It is not recommended to be used in "normal" + * applications directly because it comes with pitfalls. Use at your own risk! + * + * @param callback The callback in which the passed isolation scope is active. (Note: In environments without async + * context strategy, the currently active isolation scope may change within execution of the callback.) + * @returns The same value that `callback` returns. + */ +export function withIsolationScope(callback: (isolationScope: Scope) => T): T { + return runWithAsyncContext(() => { + return callback(getIsolationScope()); + }); +} + /** * Starts a new `Transaction` and returns it. This is the entry point to manual tracing instrumentation. * diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index e277c01f2dbe..4e6c658f5305 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -29,6 +29,7 @@ export { setTags, setUser, withScope, + withIsolationScope, getClient, getCurrentScope, startSession, diff --git a/packages/core/test/lib/async-context.test.ts b/packages/core/test/lib/async-context.test.ts new file mode 100644 index 000000000000..58b44c922b09 --- /dev/null +++ b/packages/core/test/lib/async-context.test.ts @@ -0,0 +1,13 @@ +import { getCurrentHub, runWithAsyncContext } from '../../src'; + +describe('runWithAsyncContext()', () => { + it('without strategy hubs should be equal', () => { + runWithAsyncContext(() => { + const hub1 = getCurrentHub(); + runWithAsyncContext(() => { + const hub2 = getCurrentHub(); + expect(hub1).toBe(hub2); + }); + }); + }); +}); diff --git a/packages/core/test/lib/scope.test.ts b/packages/core/test/lib/scope.test.ts index 87af429d0859..316af3642c1c 100644 --- a/packages/core/test/lib/scope.test.ts +++ b/packages/core/test/lib/scope.test.ts @@ -1,5 +1,5 @@ import type { Attachment, Breadcrumb, Client, Event } from '@sentry/types'; -import { applyScopeDataToEvent } from '../../src'; +import { applyScopeDataToEvent, getCurrentScope, getIsolationScope, withIsolationScope } from '../../src'; import { Scope, getGlobalScope, setGlobalScope } from '../../src/scope'; describe('Scope', () => { @@ -465,3 +465,41 @@ describe('Scope', () => { }); }); }); + +describe('isolation scope', () => { + describe('withIsolationScope()', () => { + it('will pass an isolation scope without Sentry.init()', done => { + expect.assertions(1); + withIsolationScope(scope => { + expect(scope).toBeDefined(); + done(); + }); + }); + + it('will make the passed isolation scope the active isolation scope within the callback', done => { + expect.assertions(1); + withIsolationScope(scope => { + expect(getIsolationScope()).toBe(scope); + done(); + }); + }); + + it('will pass an isolation scope that is different from the current active scope', done => { + expect.assertions(1); + withIsolationScope(scope => { + expect(getCurrentScope()).not.toBe(scope); + done(); + }); + }); + + it('will always make the inner most passed scope the current scope when nesting calls', done => { + expect.assertions(1); + withIsolationScope(_scope1 => { + withIsolationScope(scope2 => { + expect(getIsolationScope()).toBe(scope2); + done(); + }); + }); + }); + }); +}); diff --git a/packages/deno/src/index.ts b/packages/deno/src/index.ts index 2658d6f31e36..cf216aa033cb 100644 --- a/packages/deno/src/index.ts +++ b/packages/deno/src/index.ts @@ -65,6 +65,7 @@ export { // eslint-disable-next-line deprecation/deprecation trace, withScope, + withIsolationScope, captureCheckIn, withMonitor, setMeasurement, diff --git a/packages/node/src/index.ts b/packages/node/src/index.ts index 21735a64d6a1..6d856d14fc39 100644 --- a/packages/node/src/index.ts +++ b/packages/node/src/index.ts @@ -65,6 +65,7 @@ export { // eslint-disable-next-line deprecation/deprecation trace, withScope, + withIsolationScope, captureCheckIn, withMonitor, setMeasurement, diff --git a/packages/node/test/async/domain.test.ts b/packages/node/test/async/domain.test.ts index 50269af65880..96f19386e63f 100644 --- a/packages/node/test/async/domain.test.ts +++ b/packages/node/test/async/domain.test.ts @@ -1,145 +1,208 @@ import type { Hub } from '@sentry/core'; +import { getIsolationScope, withIsolationScope } from '@sentry/core'; import { getCurrentHub, runWithAsyncContext, setAsyncContextStrategy } from '@sentry/core'; import { setDomainAsyncContextStrategy } from '../../src/async/domain'; -describe('domains', () => { - afterAll(() => { +describe('setDomainAsyncContextStrategy()', () => { + afterEach(() => { // clear the strategy setAsyncContextStrategy(undefined); }); - test('hub scope inheritance', () => { - setDomainAsyncContextStrategy(); + describe('with withIsolationScope()', () => { + it('forks the isolation scope (creating a new one)', done => { + expect.assertions(7); + setDomainAsyncContextStrategy(); - const globalHub = getCurrentHub(); - // eslint-disable-next-line deprecation/deprecation - globalHub.setExtra('a', 'b'); + const topLevelIsolationScope = getIsolationScope(); + topLevelIsolationScope.setTag('val1', true); - runWithAsyncContext(() => { - const hub1 = getCurrentHub(); - expect(hub1).toEqual(globalHub); + withIsolationScope(isolationScope1 => { + expect(isolationScope1).not.toBe(topLevelIsolationScope); + expect(isolationScope1.getScopeData().tags['val1']).toBe(true); + isolationScope1.setTag('val2', true); + topLevelIsolationScope.setTag('val3', true); - // eslint-disable-next-line deprecation/deprecation - hub1.setExtra('c', 'd'); - expect(hub1).not.toEqual(globalHub); + withIsolationScope(isolationScope2 => { + expect(isolationScope2).not.toBe(isolationScope1); + expect(isolationScope2).not.toBe(topLevelIsolationScope); + expect(isolationScope2.getScopeData().tags['val1']).toBe(true); + expect(isolationScope2.getScopeData().tags['val2']).toBe(true); + expect(isolationScope2.getScopeData().tags['val3']).toBeUndefined(); - runWithAsyncContext(() => { - const hub2 = getCurrentHub(); - expect(hub2).toEqual(hub1); - expect(hub2).not.toEqual(globalHub); + done(); + }); + }); + }); - // eslint-disable-next-line deprecation/deprecation - hub2.setExtra('e', 'f'); - expect(hub2).not.toEqual(hub1); + it('correctly keeps track of isolation scope across asynchronous operations', done => { + expect.assertions(7); + setDomainAsyncContextStrategy(); + + const topLevelIsolationScope = getIsolationScope(); + expect(getIsolationScope()).toBe(topLevelIsolationScope); + + withIsolationScope(isolationScope1 => { + setTimeout(() => { + expect(getIsolationScope()).toBe(isolationScope1); + + withIsolationScope(isolationScope2 => { + setTimeout(() => { + expect(getIsolationScope()).toBe(isolationScope2); + }, 100); + }); + + setTimeout(() => { + expect(getIsolationScope()).toBe(isolationScope1); + done(); + }, 200); + + expect(getIsolationScope()).toBe(isolationScope1); + }, 100); }); + + setTimeout(() => { + expect(getIsolationScope()).toBe(topLevelIsolationScope); + }, 200); + + expect(getIsolationScope()).toBe(topLevelIsolationScope); }); }); - test('async hub scope inheritance', async () => { - setDomainAsyncContextStrategy(); + describe('with runWithAsyncContext()', () => { + test('hub scope inheritance', () => { + setDomainAsyncContextStrategy(); + + const globalHub = getCurrentHub(); + // eslint-disable-next-line deprecation/deprecation + globalHub.setExtra('a', 'b'); + + runWithAsyncContext(() => { + const hub1 = getCurrentHub(); + expect(hub1).toEqual(globalHub); + + // eslint-disable-next-line deprecation/deprecation + hub1.setExtra('c', 'd'); + expect(hub1).not.toEqual(globalHub); + + runWithAsyncContext(() => { + const hub2 = getCurrentHub(); + expect(hub2).toEqual(hub1); + expect(hub2).not.toEqual(globalHub); - async function addRandomExtra(hub: Hub, key: string): Promise { - return new Promise(resolve => { - setTimeout(() => { // eslint-disable-next-line deprecation/deprecation - hub.setExtra(key, Math.random()); - resolve(); - }, 100); + hub2.setExtra('e', 'f'); + expect(hub2).not.toEqual(hub1); + }); }); - } + }); - const globalHub = getCurrentHub(); - await addRandomExtra(globalHub, 'a'); + test('async hub scope inheritance', async () => { + setDomainAsyncContextStrategy(); - await runWithAsyncContext(async () => { - const hub1 = getCurrentHub(); - expect(hub1).toEqual(globalHub); + async function addRandomExtra(hub: Hub, key: string): Promise { + return new Promise(resolve => { + setTimeout(() => { + // eslint-disable-next-line deprecation/deprecation + hub.setExtra(key, Math.random()); + resolve(); + }, 100); + }); + } - await addRandomExtra(hub1, 'b'); - expect(hub1).not.toEqual(globalHub); + const globalHub = getCurrentHub(); + await addRandomExtra(globalHub, 'a'); await runWithAsyncContext(async () => { - const hub2 = getCurrentHub(); - expect(hub2).toEqual(hub1); - expect(hub2).not.toEqual(globalHub); + const hub1 = getCurrentHub(); + expect(hub1).toEqual(globalHub); + + await addRandomExtra(hub1, 'b'); + expect(hub1).not.toEqual(globalHub); + + await runWithAsyncContext(async () => { + const hub2 = getCurrentHub(); + expect(hub2).toEqual(hub1); + expect(hub2).not.toEqual(globalHub); - await addRandomExtra(hub1, 'c'); - expect(hub2).not.toEqual(hub1); + await addRandomExtra(hub1, 'c'); + expect(hub2).not.toEqual(hub1); + }); }); }); - }); - test('hub single instance', () => { - setDomainAsyncContextStrategy(); + test('hub single instance', () => { + setDomainAsyncContextStrategy(); - runWithAsyncContext(() => { - const hub = getCurrentHub(); - expect(hub).toBe(getCurrentHub()); + runWithAsyncContext(() => { + const hub = getCurrentHub(); + expect(hub).toBe(getCurrentHub()); + }); }); - }); - test('within a domain not reused', () => { - setDomainAsyncContextStrategy(); + test('within a domain not reused', () => { + setDomainAsyncContextStrategy(); - runWithAsyncContext(() => { - const hub1 = getCurrentHub(); runWithAsyncContext(() => { - const hub2 = getCurrentHub(); - expect(hub1).not.toBe(hub2); + const hub1 = getCurrentHub(); + runWithAsyncContext(() => { + const hub2 = getCurrentHub(); + expect(hub1).not.toBe(hub2); + }); }); }); - }); - test('within a domain reused when requested', () => { - setDomainAsyncContextStrategy(); + test('within a domain reused when requested', () => { + setDomainAsyncContextStrategy(); - runWithAsyncContext(() => { - const hub1 = getCurrentHub(); - runWithAsyncContext( - () => { - const hub2 = getCurrentHub(); - expect(hub1).toBe(hub2); - }, - { reuseExisting: true }, - ); + runWithAsyncContext(() => { + const hub1 = getCurrentHub(); + runWithAsyncContext( + () => { + const hub2 = getCurrentHub(); + expect(hub1).toBe(hub2); + }, + { reuseExisting: true }, + ); + }); }); - }); - test('concurrent hub contexts', done => { - setDomainAsyncContextStrategy(); + test('concurrent hub contexts', done => { + setDomainAsyncContextStrategy(); - let d1done = false; - let d2done = false; + let d1done = false; + let d2done = false; - runWithAsyncContext(() => { - const hub = getCurrentHub(); - // eslint-disable-next-line deprecation/deprecation - hub.getStack().push({ client: 'process' } as any); - // eslint-disable-next-line deprecation/deprecation - expect(hub.getStack()[1]).toEqual({ client: 'process' }); - // Just in case so we don't have to worry which one finishes first - // (although it always should be d2) - setTimeout(() => { - d1done = true; - if (d2done) { - done(); - } - }, 0); - }); + runWithAsyncContext(() => { + const hub = getCurrentHub(); + // eslint-disable-next-line deprecation/deprecation + hub.getStack().push({ client: 'process' } as any); + // eslint-disable-next-line deprecation/deprecation + expect(hub.getStack()[1]).toEqual({ client: 'process' }); + // Just in case so we don't have to worry which one finishes first + // (although it always should be d2) + setTimeout(() => { + d1done = true; + if (d2done) { + done(); + } + }, 0); + }); - runWithAsyncContext(() => { - const hub = getCurrentHub(); - // eslint-disable-next-line deprecation/deprecation - hub.getStack().push({ client: 'local' } as any); - // eslint-disable-next-line deprecation/deprecation - expect(hub.getStack()[1]).toEqual({ client: 'local' }); - setTimeout(() => { - d2done = true; - if (d1done) { - done(); - } - }, 0); + runWithAsyncContext(() => { + const hub = getCurrentHub(); + // eslint-disable-next-line deprecation/deprecation + hub.getStack().push({ client: 'local' } as any); + // eslint-disable-next-line deprecation/deprecation + expect(hub.getStack()[1]).toEqual({ client: 'local' }); + setTimeout(() => { + d2done = true; + if (d1done) { + done(); + } + }, 0); + }); }); }); }); diff --git a/packages/node/test/async/hooks.test.ts b/packages/node/test/async/hooks.test.ts index 8c086c66e25d..f42619839043 100644 --- a/packages/node/test/async/hooks.test.ts +++ b/packages/node/test/async/hooks.test.ts @@ -1,156 +1,210 @@ import type { Hub } from '@sentry/core'; +import { getIsolationScope } from '@sentry/core'; +import { withIsolationScope } from '@sentry/core'; import { getCurrentHub, runWithAsyncContext, setAsyncContextStrategy } from '@sentry/core'; import { setHooksAsyncContextStrategy } from '../../src/async/hooks'; import { conditionalTest } from '../utils'; -conditionalTest({ min: 12 })('async_hooks', () => { - afterAll(() => { +conditionalTest({ min: 12 })('setHooksAsyncContextStrategy()', () => { + afterEach(() => { // clear the strategy setAsyncContextStrategy(undefined); }); - test('without strategy hubs should be equal', () => { - runWithAsyncContext(() => { - const hub1 = getCurrentHub(); - runWithAsyncContext(() => { - const hub2 = getCurrentHub(); - expect(hub1).toBe(hub2); + describe('with withIsolationScope()', () => { + it('forks the isolation scope (creating a new one)', done => { + expect.assertions(7); + setHooksAsyncContextStrategy(); + + const topLevelIsolationScope = getIsolationScope(); + topLevelIsolationScope.setTag('val1', true); + + withIsolationScope(isolationScope1 => { + expect(isolationScope1).not.toBe(topLevelIsolationScope); + expect(isolationScope1.getScopeData().tags['val1']).toBe(true); + isolationScope1.setTag('val2', true); + topLevelIsolationScope.setTag('val3', true); + + withIsolationScope(isolationScope2 => { + expect(isolationScope2).not.toBe(isolationScope1); + expect(isolationScope2).not.toBe(topLevelIsolationScope); + expect(isolationScope2.getScopeData().tags['val1']).toBe(true); + expect(isolationScope2.getScopeData().tags['val2']).toBe(true); + expect(isolationScope2.getScopeData().tags['val3']).toBeUndefined(); + + done(); + }); }); }); - }); - test('hub scope inheritance', () => { - setHooksAsyncContextStrategy(); + it('correctly keeps track of isolation scope across asynchronous operations', done => { + expect.assertions(7); + setHooksAsyncContextStrategy(); - const globalHub = getCurrentHub(); - // eslint-disable-next-line deprecation/deprecation - globalHub.setExtra('a', 'b'); + const topLevelIsolationScope = getIsolationScope(); + expect(getIsolationScope()).toBe(topLevelIsolationScope); - runWithAsyncContext(() => { - const hub1 = getCurrentHub(); - expect(hub1).toEqual(globalHub); + withIsolationScope(isolationScope1 => { + setTimeout(() => { + expect(getIsolationScope()).toBe(isolationScope1); - // eslint-disable-next-line deprecation/deprecation - hub1.setExtra('c', 'd'); - expect(hub1).not.toEqual(globalHub); + withIsolationScope(isolationScope2 => { + setTimeout(() => { + expect(getIsolationScope()).toBe(isolationScope2); + }, 100); + }); - runWithAsyncContext(() => { - const hub2 = getCurrentHub(); - expect(hub2).toEqual(hub1); - expect(hub2).not.toEqual(globalHub); + setTimeout(() => { + expect(getIsolationScope()).toBe(isolationScope1); + done(); + }, 200); - // eslint-disable-next-line deprecation/deprecation - hub2.setExtra('e', 'f'); - expect(hub2).not.toEqual(hub1); + expect(getIsolationScope()).toBe(isolationScope1); + }, 100); }); + + setTimeout(() => { + expect(getIsolationScope()).toBe(topLevelIsolationScope); + }, 200); + + expect(getIsolationScope()).toBe(topLevelIsolationScope); }); }); - test('async hub scope inheritance', async () => { - setHooksAsyncContextStrategy(); + describe('with runWithAsyncContext()', () => { + test('hub scope inheritance', () => { + setHooksAsyncContextStrategy(); + + const globalHub = getCurrentHub(); + // eslint-disable-next-line deprecation/deprecation + globalHub.setExtra('a', 'b'); + + runWithAsyncContext(() => { + const hub1 = getCurrentHub(); + expect(hub1).toEqual(globalHub); + + // eslint-disable-next-line deprecation/deprecation + hub1.setExtra('c', 'd'); + expect(hub1).not.toEqual(globalHub); + + runWithAsyncContext(() => { + const hub2 = getCurrentHub(); + expect(hub2).toEqual(hub1); + expect(hub2).not.toEqual(globalHub); - async function addRandomExtra(hub: Hub, key: string): Promise { - return new Promise(resolve => { - setTimeout(() => { // eslint-disable-next-line deprecation/deprecation - hub.setExtra(key, Math.random()); - resolve(); - }, 100); + hub2.setExtra('e', 'f'); + expect(hub2).not.toEqual(hub1); + }); }); - } + }); - const globalHub = getCurrentHub(); - await addRandomExtra(globalHub, 'a'); + test('async hub scope inheritance', async () => { + setHooksAsyncContextStrategy(); - await runWithAsyncContext(async () => { - const hub1 = getCurrentHub(); - expect(hub1).toEqual(globalHub); + async function addRandomExtra(hub: Hub, key: string): Promise { + return new Promise(resolve => { + setTimeout(() => { + // eslint-disable-next-line deprecation/deprecation + hub.setExtra(key, Math.random()); + resolve(); + }, 100); + }); + } - await addRandomExtra(hub1, 'b'); - expect(hub1).not.toEqual(globalHub); + const globalHub = getCurrentHub(); + await addRandomExtra(globalHub, 'a'); await runWithAsyncContext(async () => { - const hub2 = getCurrentHub(); - expect(hub2).toEqual(hub1); - expect(hub2).not.toEqual(globalHub); + const hub1 = getCurrentHub(); + expect(hub1).toEqual(globalHub); + + await addRandomExtra(hub1, 'b'); + expect(hub1).not.toEqual(globalHub); + + await runWithAsyncContext(async () => { + const hub2 = getCurrentHub(); + expect(hub2).toEqual(hub1); + expect(hub2).not.toEqual(globalHub); - await addRandomExtra(hub1, 'c'); - expect(hub2).not.toEqual(hub1); + await addRandomExtra(hub1, 'c'); + expect(hub2).not.toEqual(hub1); + }); }); }); - }); - test('context single instance', () => { - setHooksAsyncContextStrategy(); + test('context single instance', () => { + setHooksAsyncContextStrategy(); - const globalHub = getCurrentHub(); - runWithAsyncContext(() => { - expect(globalHub).not.toBe(getCurrentHub()); + const globalHub = getCurrentHub(); + runWithAsyncContext(() => { + expect(globalHub).not.toBe(getCurrentHub()); + }); }); - }); - test('context within a context not reused', () => { - setHooksAsyncContextStrategy(); + test('context within a context not reused', () => { + setHooksAsyncContextStrategy(); - runWithAsyncContext(() => { - const hub1 = getCurrentHub(); runWithAsyncContext(() => { - const hub2 = getCurrentHub(); - expect(hub1).not.toBe(hub2); + const hub1 = getCurrentHub(); + runWithAsyncContext(() => { + const hub2 = getCurrentHub(); + expect(hub1).not.toBe(hub2); + }); }); }); - }); - test('context within a context reused when requested', () => { - setHooksAsyncContextStrategy(); + test('context within a context reused when requested', () => { + setHooksAsyncContextStrategy(); - runWithAsyncContext(() => { - const hub1 = getCurrentHub(); - runWithAsyncContext( - () => { - const hub2 = getCurrentHub(); - expect(hub1).toBe(hub2); - }, - { reuseExisting: true }, - ); + runWithAsyncContext(() => { + const hub1 = getCurrentHub(); + runWithAsyncContext( + () => { + const hub2 = getCurrentHub(); + expect(hub1).toBe(hub2); + }, + { reuseExisting: true }, + ); + }); }); - }); - test('concurrent hub contexts', done => { - setHooksAsyncContextStrategy(); + test('concurrent hub contexts', done => { + setHooksAsyncContextStrategy(); - let d1done = false; - let d2done = false; + let d1done = false; + let d2done = false; - runWithAsyncContext(() => { - const hub = getCurrentHub(); - // eslint-disable-next-line deprecation/deprecation - hub.getStack().push({ client: 'process' } as any); - // eslint-disable-next-line deprecation/deprecation - expect(hub.getStack()[1]).toEqual({ client: 'process' }); - // Just in case so we don't have to worry which one finishes first - // (although it always should be d2) - setTimeout(() => { - d1done = true; - if (d2done) { - done(); - } - }, 0); - }); + runWithAsyncContext(() => { + const hub = getCurrentHub(); + // eslint-disable-next-line deprecation/deprecation + hub.getStack().push({ client: 'process' } as any); + // eslint-disable-next-line deprecation/deprecation + expect(hub.getStack()[1]).toEqual({ client: 'process' }); + // Just in case so we don't have to worry which one finishes first + // (although it always should be d2) + setTimeout(() => { + d1done = true; + if (d2done) { + done(); + } + }, 0); + }); - runWithAsyncContext(() => { - const hub = getCurrentHub(); - // eslint-disable-next-line deprecation/deprecation - hub.getStack().push({ client: 'local' } as any); - // eslint-disable-next-line deprecation/deprecation - expect(hub.getStack()[1]).toEqual({ client: 'local' }); - setTimeout(() => { - d2done = true; - if (d1done) { - done(); - } - }, 0); + runWithAsyncContext(() => { + const hub = getCurrentHub(); + // eslint-disable-next-line deprecation/deprecation + hub.getStack().push({ client: 'local' } as any); + // eslint-disable-next-line deprecation/deprecation + expect(hub.getStack()[1]).toEqual({ client: 'local' }); + setTimeout(() => { + d2done = true; + if (d1done) { + done(); + } + }, 0); + }); }); }); }); diff --git a/packages/remix/src/index.server.ts b/packages/remix/src/index.server.ts index f30b5311d0f6..c227d5d1322e 100644 --- a/packages/remix/src/index.server.ts +++ b/packages/remix/src/index.server.ts @@ -45,6 +45,7 @@ export { // eslint-disable-next-line deprecation/deprecation trace, withScope, + withIsolationScope, autoDiscoverNodePerformanceMonitoringIntegrations, makeNodeTransport, defaultIntegrations, diff --git a/packages/serverless/src/index.ts b/packages/serverless/src/index.ts index 749909e39272..da5718ed2ca9 100644 --- a/packages/serverless/src/index.ts +++ b/packages/serverless/src/index.ts @@ -45,6 +45,7 @@ export { // eslint-disable-next-line deprecation/deprecation startTransaction, withScope, + withIsolationScope, NodeClient, makeNodeTransport, close, diff --git a/packages/sveltekit/src/server/index.ts b/packages/sveltekit/src/server/index.ts index e224df7421a2..0367f4153094 100644 --- a/packages/sveltekit/src/server/index.ts +++ b/packages/sveltekit/src/server/index.ts @@ -43,6 +43,7 @@ export { // eslint-disable-next-line deprecation/deprecation trace, withScope, + withIsolationScope, autoDiscoverNodePerformanceMonitoringIntegrations, makeNodeTransport, defaultIntegrations, diff --git a/packages/vercel-edge/src/index.ts b/packages/vercel-edge/src/index.ts index 515b9c8691b7..8fcc124256dc 100644 --- a/packages/vercel-edge/src/index.ts +++ b/packages/vercel-edge/src/index.ts @@ -65,6 +65,7 @@ export { // eslint-disable-next-line deprecation/deprecation trace, withScope, + withIsolationScope, captureCheckIn, withMonitor, setMeasurement,