@@ -3,6 +3,7 @@ import type { ClientOptions, Scope, SentrySpanArguments, Span, SpanTimeInput, St
33import { propagationContextFromHeaders } from '@sentry/utils' ;
44import type { AsyncContextStrategy } from '../asyncContext' ;
55import { getMainCarrier } from '../asyncContext' ;
6+
67import { getClient , getCurrentScope , getIsolationScope , withScope } from '../currentScopes' ;
78
89import { getAsyncContextStrategy } from '../hub' ;
@@ -25,6 +26,8 @@ import { SentrySpan } from './sentrySpan';
2526import { SPAN_STATUS_ERROR } from './spanstatus' ;
2627import { setCapturedScopesOnSpan } from './utils' ;
2728
29+ const SUPPRESS_TRACING_KEY = '__SENTRY_SUPPRESS_TRACING__' ;
30+
2831/**
2932 * Wraps a function with a transaction/span and finishes the span after the function is done.
3033 * The created span is the active span and will be used as parent by other spans created inside the function
@@ -204,6 +207,20 @@ export function withActiveSpan<T>(span: Span | null, callback: (scope: Scope) =>
204207 } ) ;
205208}
206209
210+ /** Suppress tracing in the given callback, ensuring no spans are generated inside of it. */
211+ export function suppressTracing < T > ( callback : ( ) => T ) : T {
212+ const acs = getAcs ( ) ;
213+
214+ if ( acs . suppressTracing ) {
215+ return acs . suppressTracing ( callback ) ;
216+ }
217+
218+ return withScope ( scope => {
219+ scope . setSDKProcessingMetadata ( { [ SUPPRESS_TRACING_KEY ] : true } ) ;
220+ return callback ( ) ;
221+ } ) ;
222+ }
223+
207224function createChildSpanOrTransaction ( {
208225 parentSpan,
209226 spanContext,
@@ -223,7 +240,7 @@ function createChildSpanOrTransaction({
223240
224241 let span : Span ;
225242 if ( parentSpan && ! forceTransaction ) {
226- span = _startChildSpan ( parentSpan , spanContext ) ;
243+ span = _startChildSpan ( parentSpan , scope , spanContext ) ;
227244 addChildSpanToSpan ( parentSpan , span ) ;
228245 } else if ( parentSpan ) {
229246 // If we forced a transaction but have a parent span, make sure to continue from the parent span, not the scope
@@ -237,6 +254,7 @@ function createChildSpanOrTransaction({
237254 parentSpanId,
238255 ...spanContext ,
239256 } ,
257+ scope ,
240258 parentSampled ,
241259 ) ;
242260
@@ -258,6 +276,7 @@ function createChildSpanOrTransaction({
258276 parentSpanId,
259277 ...spanContext ,
260278 } ,
279+ scope ,
261280 parentSampled ,
262281 ) ;
263282
@@ -296,22 +315,24 @@ function getAcs(): AsyncContextStrategy {
296315 return getAsyncContextStrategy ( carrier ) ;
297316}
298317
299- function _startRootSpan ( spanArguments : SentrySpanArguments , parentSampled ?: boolean ) : SentrySpan {
318+ function _startRootSpan ( spanArguments : SentrySpanArguments , scope : Scope , parentSampled ?: boolean ) : SentrySpan {
300319 const client = getClient ( ) ;
301320 const options : Partial < ClientOptions > = ( client && client . getOptions ( ) ) || { } ;
302321
303322 const { name = '' , attributes } = spanArguments ;
304- const [ sampled , sampleRate ] = sampleSpan ( options , {
305- name,
306- parentSampled,
307- attributes,
308- transactionContext : {
309- name,
310- parentSampled,
311- } ,
312- } ) ;
313-
314- const transaction = new SentrySpan ( {
323+ const [ sampled , sampleRate ] = scope . getScopeData ( ) . sdkProcessingMetadata [ SUPPRESS_TRACING_KEY ]
324+ ? [ false ]
325+ : sampleSpan ( options , {
326+ name,
327+ parentSampled,
328+ attributes,
329+ transactionContext : {
330+ name,
331+ parentSampled,
332+ } ,
333+ } ) ;
334+
335+ const rootSpan = new SentrySpan ( {
315336 ...spanArguments ,
316337 attributes : {
317338 [ SEMANTIC_ATTRIBUTE_SENTRY_SOURCE ] : 'custom' ,
@@ -320,30 +341,32 @@ function _startRootSpan(spanArguments: SentrySpanArguments, parentSampled?: bool
320341 sampled,
321342 } ) ;
322343 if ( sampleRate !== undefined ) {
323- transaction . setAttribute ( SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE , sampleRate ) ;
344+ rootSpan . setAttribute ( SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE , sampleRate ) ;
324345 }
325346
326347 if ( client ) {
327- client . emit ( 'spanStart' , transaction ) ;
348+ client . emit ( 'spanStart' , rootSpan ) ;
328349 }
329350
330- return transaction ;
351+ return rootSpan ;
331352}
332353
333354/**
334355 * Creates a new `Span` while setting the current `Span.id` as `parentSpanId`.
335356 * This inherits the sampling decision from the parent span.
336357 */
337- function _startChildSpan ( parentSpan : Span , spanArguments : SentrySpanArguments ) : SentrySpan {
358+ function _startChildSpan ( parentSpan : Span , scope : Scope , spanArguments : SentrySpanArguments ) : Span {
338359 const { spanId, traceId } = parentSpan . spanContext ( ) ;
339- const sampled = spanIsSampled ( parentSpan ) ;
360+ const sampled = scope . getScopeData ( ) . sdkProcessingMetadata [ SUPPRESS_TRACING_KEY ] ? false : spanIsSampled ( parentSpan ) ;
340361
341- const childSpan = new SentrySpan ( {
342- ...spanArguments ,
343- parentSpanId : spanId ,
344- traceId,
345- sampled,
346- } ) ;
362+ const childSpan = sampled
363+ ? new SentrySpan ( {
364+ ...spanArguments ,
365+ parentSpanId : spanId ,
366+ traceId,
367+ sampled,
368+ } )
369+ : new SentryNonRecordingSpan ( ) ;
347370
348371 addChildSpanToSpan ( parentSpan , childSpan ) ;
349372
0 commit comments