@@ -371,20 +371,21 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
371
371
/**
372
372
* @inheritDoc
373
373
*/
374
- public recordDroppedEvent ( reason : EventDropReason , category : DataCategory , _event ?: Event ) : void {
375
- // Note: we use `event` in replay, where we overwrite this hook.
376
-
374
+ public recordDroppedEvent ( reason : EventDropReason , category : DataCategory , eventOrCount ?: Event | number ) : void {
377
375
if ( this . _options . sendClientReports ) {
376
+ // TODO v9: We do not need the `event` passed as third argument anymore, and can possibly remove this overload
377
+ // If event is passed as third argument, we assume this is a count of 1
378
+ const count = typeof eventOrCount === 'number' ? eventOrCount : 1 ;
379
+
378
380
// We want to track each category (error, transaction, session, replay_event) separately
379
381
// but still keep the distinction between different type of outcomes.
380
382
// We could use nested maps, but it's much easier to read and type this way.
381
383
// A correct type for map-based implementation if we want to go that route
382
384
// would be `Partial<Record<SentryRequestType, Partial<Record<Outcome, number>>>>`
383
385
// With typescript 4.1 we could even use template literal types
384
386
const key = `${ reason } :${ category } ` ;
385
- DEBUG_BUILD && logger . log ( `Adding outcome: "${ key } "` ) ;
386
-
387
- this . _outcomes [ key ] = ( this . _outcomes [ key ] || 0 ) + 1 ;
387
+ DEBUG_BUILD && logger . log ( `Recording outcome: "${ key } "${ count > 1 ? ` (${ count } times)` : '' } ` ) ;
388
+ this . _outcomes [ key ] = ( this . _outcomes [ key ] || 0 ) + count ;
388
389
}
389
390
}
390
391
@@ -794,11 +795,11 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
794
795
. then ( processedEvent => {
795
796
if ( processedEvent === null ) {
796
797
this . recordDroppedEvent ( 'before_send' , dataCategory , event ) ;
797
- if ( isTransactionEvent ( event ) ) {
798
+ if ( isTransaction ) {
798
799
const spans = event . spans || [ ] ;
799
800
// the transaction itself counts as one span, plus all the child spans that are added
800
801
const spanCount = 1 + spans . length ;
801
- this . _outcomes [ 'span' ] = ( this . _outcomes [ 'span' ] || 0 ) + spanCount ;
802
+ this . recordDroppedEvent ( 'before_send' , 'span' , spanCount ) ;
802
803
}
803
804
throw new SentryError ( `${ beforeSendLabel } returned \`null\`, will not send event.` , 'log' ) ;
804
805
}
@@ -808,6 +809,18 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
808
809
this . _updateSessionFromEvent ( session , processedEvent ) ;
809
810
}
810
811
812
+ if ( isTransaction ) {
813
+ const spanCountBefore =
814
+ ( processedEvent . sdkProcessingMetadata && processedEvent . sdkProcessingMetadata . spanCountBeforeProcessing ) ||
815
+ 0 ;
816
+ const spanCountAfter = processedEvent . spans ? processedEvent . spans . length : 0 ;
817
+
818
+ const droppedSpanCount = spanCountBefore - spanCountAfter ;
819
+ if ( droppedSpanCount > 0 ) {
820
+ this . recordDroppedEvent ( 'before_send' , 'span' , droppedSpanCount ) ;
821
+ }
822
+ }
823
+
811
824
// None of the Sentry built event processor will update transaction name,
812
825
// so if the transaction name has been changed by an event processor, we know
813
826
// it has to come from custom event processor added by a user
@@ -973,6 +986,15 @@ function processBeforeSend(
973
986
}
974
987
975
988
if ( beforeSendTransaction ) {
989
+ if ( event . spans ) {
990
+ // We store the # of spans before processing in SDK metadata,
991
+ // so we can compare it afterwards to determine how many spans were dropped
992
+ const spanCountBefore = event . spans . length ;
993
+ event . sdkProcessingMetadata = {
994
+ ...event . sdkProcessingMetadata ,
995
+ spanCountBeforeProcessing : spanCountBefore ,
996
+ } ;
997
+ }
976
998
return beforeSendTransaction ( event , hint ) ;
977
999
}
978
1000
}
0 commit comments