diff --git a/packages/cloudflare/src/async.ts b/packages/cloudflare/src/async.ts index cd20a8d083de..66f2d439a3ce 100644 --- a/packages/cloudflare/src/async.ts +++ b/packages/cloudflare/src/async.ts @@ -64,7 +64,16 @@ export function setAsyncLocalStorageAsyncContextStrategy(): void { }); } + // In contrast to the browser, we can rely on async context isolation here + function suppressTracing(callback: () => T): T { + return withScope(scope => { + scope.setSDKProcessingMetadata({ __SENTRY_SUPPRESS_TRACING__: true }); + return callback(); + }); + } + setAsyncContextStrategy({ + suppressTracing, withScope, withSetScope, withIsolationScope, diff --git a/packages/core/src/tracing/trace.ts b/packages/core/src/tracing/trace.ts index a96159692ac3..427e4ebb0bf6 100644 --- a/packages/core/src/tracing/trace.ts +++ b/packages/core/src/tracing/trace.ts @@ -253,8 +253,15 @@ export function suppressTracing(callback: () => T): T { } return withScope(scope => { + // Note: We do not wait for the callback to finish before we reset the metadata + // the reason for this is that otherwise, in the browser this can lead to very weird behavior + // as there is only a single top scope, if the callback takes longer to finish, + // other, unrelated spans may also be suppressed, which we do not want + // so instead, we only suppress tracing synchronoysly in the browser scope.setSDKProcessingMetadata({ [SUPPRESS_TRACING_KEY]: true }); - return callback(); + const res = callback(); + scope.setSDKProcessingMetadata({ [SUPPRESS_TRACING_KEY]: undefined }); + return res; }); } diff --git a/packages/core/test/lib/tracing/trace.test.ts b/packages/core/test/lib/tracing/trace.test.ts index 83f4b150a6d6..6d25afe13d3e 100644 --- a/packages/core/test/lib/tracing/trace.test.ts +++ b/packages/core/test/lib/tracing/trace.test.ts @@ -1975,6 +1975,40 @@ describe('suppressTracing', () => { expect(spanIsSampled(child)).toBe(false); }); }); + + it('works with parallel processes', async () => { + const span = suppressTracing(() => { + return startInactiveSpan({ name: 'span' }); + }); + + // Note: This is unintuitive, but it is the expected behavior + // because we only suppress tracing synchronously in the browser + const span2Promise = suppressTracing(async () => { + await new Promise(resolve => setTimeout(resolve, 100)); + return startInactiveSpan({ name: 'span2' }); + }); + + const span3Promise = suppressTracing(async () => { + const span = startInactiveSpan({ name: 'span3' }); + await new Promise(resolve => setTimeout(resolve, 100)); + return span; + }); + + const span4 = suppressTracing(() => { + return startInactiveSpan({ name: 'span' }); + }); + + const span5 = startInactiveSpan({ name: 'span5' }); + + const span2 = await span2Promise; + const span3 = await span3Promise; + + expect(spanIsSampled(span)).toBe(false); + expect(spanIsSampled(span2)).toBe(true); + expect(spanIsSampled(span3)).toBe(false); + expect(spanIsSampled(span4)).toBe(false); + expect(spanIsSampled(span5)).toBe(true); + }); }); describe('startNewTrace', () => { diff --git a/packages/opentelemetry/test/trace.test.ts b/packages/opentelemetry/test/trace.test.ts index f9aed823a4a4..d8432172a601 100644 --- a/packages/opentelemetry/test/trace.test.ts +++ b/packages/opentelemetry/test/trace.test.ts @@ -1921,6 +1921,38 @@ describe('suppressTracing', () => { expect(spanIsSampled(child)).toBe(false); }); }); + + it('works with parallel processes', async () => { + const span = suppressTracing(() => { + return startInactiveSpan({ name: 'span' }); + }); + + const span2Promise = suppressTracing(async () => { + await new Promise(resolve => setTimeout(resolve, 100)); + return startInactiveSpan({ name: 'span2' }); + }); + + const span3Promise = suppressTracing(async () => { + const span = startInactiveSpan({ name: 'span3' }); + await new Promise(resolve => setTimeout(resolve, 100)); + return span; + }); + + const span4 = suppressTracing(() => { + return startInactiveSpan({ name: 'span' }); + }); + + const span5 = startInactiveSpan({ name: 'span5' }); + + const span2 = await span2Promise; + const span3 = await span3Promise; + + expect(spanIsSampled(span)).toBe(false); + expect(spanIsSampled(span2)).toBe(false); + expect(spanIsSampled(span3)).toBe(false); + expect(spanIsSampled(span4)).toBe(false); + expect(spanIsSampled(span5)).toBe(true); + }); }); function getSpanName(span: AbstractSpan): string | undefined { pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy