Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Record dropped spans #4172

Merged
merged 25 commits into from
Jul 23, 2024
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
eb7f314
Record dropped spans in sentry client
denrase Jul 16, 2024
4bf9e23
Format code
getsentry-bot Jul 16, 2024
16b8a0a
record lost spans in hub
denrase Jul 17, 2024
cdee670
Merge branch 'feat/report-dropped-spans' of github.com:getsentry/sent…
denrase Jul 17, 2024
a8beddc
Format code
getsentry-bot Jul 17, 2024
c198aae
record dropped spans in SentryHttpTrasnport
denrase Jul 17, 2024
0ff95a2
Merge branch 'feat/report-dropped-spans' of github.com:getsentry/sent…
denrase Jul 17, 2024
be6c562
Merge branch 'main' into feat/report-dropped-spans
denrase Jul 17, 2024
70cdf0c
Format code
getsentry-bot Jul 17, 2024
673d90b
add changelog entry
denrase Jul 17, 2024
a9efc91
Merge branch 'feat/report-dropped-spans' of github.com:getsentry/sent…
denrase Jul 17, 2024
0815939
Merge branch 'main' into feat/report-dropped-spans
denrase Jul 17, 2024
317b53b
fix changelog
denrase Jul 17, 2024
f7421ad
update enum case order
denrase Jul 17, 2024
572adda
change const order to reflect enum
denrase Jul 17, 2024
0243173
empty spans should also be counted
denrase Jul 17, 2024
9ccf0af
disable file length lint in test
denrase Jul 17, 2024
248f65e
move methoud out of preprocessor directives
denrase Jul 17, 2024
2d003d0
Format code
getsentry-bot Jul 17, 2024
6a0c4ee
use isEqualToString for string comparison
denrase Jul 17, 2024
2f8aa96
Merge branch 'feat/report-dropped-spans' of github.com:getsentry/sent…
denrase Jul 17, 2024
68e6bf2
add kSentryDataCategoryNameSpan to header
denrase Jul 17, 2024
5d8e18c
fix SentryDataCategoryMapperTests
denrase Jul 17, 2024
140acc7
use elvis operator
denrase Jul 22, 2024
b125bd4
Merge branch 'main' into feat/report-dropped-spans
denrase Jul 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## Unreleased

### Features

- Record dropped spans (#4172)

## 8.31.1

### Fixes
Expand Down
9 changes: 9 additions & 0 deletions SentryTestUtils/Invocations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@
}
}

public func get(_ index: Int) -> T? {
return queue.sync {
guard self._invocations.indices.contains(index) else {
return nil

Check warning on line 47 in SentryTestUtils/Invocations.swift

View check run for this annotation

Codecov / codecov/patch

SentryTestUtils/Invocations.swift#L47

Added line #L47 was not covered by tests
}
return self._invocations[index]
}
}

public func record(_ invocation: T) {
queue.async {
self._invocations.append(invocation)
Expand Down
5 changes: 5 additions & 0 deletions SentryTestUtils/TestClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,11 @@ public class TestClient: SentryClient {
recordLostEvents.record((category, reason))
}

public var recordLostEventsWithQauntity = Invocations<(category: SentryDataCategory, reason: SentryDiscardReason, quantity: UInt)>()
public override func recordLostEvent(_ category: SentryDataCategory, reason: SentryDiscardReason, quantity: UInt) {
recordLostEventsWithQauntity.record((category, reason, quantity))
}

public var flushInvocations = Invocations<TimeInterval>()
public override func flush(timeout: TimeInterval) {
flushInvocations.record(timeout)
Expand Down
5 changes: 5 additions & 0 deletions SentryTestUtils/TestTransport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ public class TestTransport: NSObject, Transport {
recordLostEvents.record((category, reason))
}

public var recordLostEventsWithCount = Invocations<(category: SentryDataCategory, reason: SentryDiscardReason, quantity: UInt)>()
public func recordLostEvent(_ category: SentryDataCategory, reason: SentryDiscardReason, quantity: UInt) {
recordLostEventsWithCount.record((category, reason, quantity))
}

public var flushInvocations = Invocations<TimeInterval>()
public func flush(_ timeout: TimeInterval) -> SentryFlushResult {
flushInvocations.record(timeout)
Expand Down
73 changes: 68 additions & 5 deletions Sources/Sentry/SentryClient.m
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,13 @@ - (void)recordLostEvent:(SentryDataCategory)category reason:(SentryDiscardReason
[self.transportAdapter recordLostEvent:category reason:reason];
}

- (void)recordLostEvent:(SentryDataCategory)category
reason:(SentryDiscardReason)reason
quantity:(NSUInteger)quantity
{
[self.transportAdapter recordLostEvent:category reason:reason quantity:quantity];
}

- (SentryEvent *_Nullable)prepareEvent:(SentryEvent *)event
withScope:(SentryScope *)scope
alwaysAttachStacktrace:(BOOL)alwaysAttachStacktrace
Expand Down Expand Up @@ -719,13 +726,35 @@ - (SentryEvent *_Nullable)prepareEvent:(SentryEvent *)event
event.user.ipAddress = @"{{auto}}";
}

BOOL eventIsATransaction
= event.type != nil && [event.type isEqualToString:SentryEnvelopeItemTypeTransaction];
BOOL eventIsATransactionClass
= eventIsATransaction && [event isKindOfClass:[SentryTransaction class]];
brustolin marked this conversation as resolved.
Show resolved Hide resolved

NSUInteger currentSpanCount;
if (eventIsATransactionClass) {
SentryTransaction *transaction = (SentryTransaction *)event;
currentSpanCount = transaction.spans.count;
} else {
currentSpanCount = 0;
}

event = [self callEventProcessors:event];
if (event == nil) {
[self recordLost:eventIsNotATransaction reason:kSentryDiscardReasonEventProcessor];
if (eventIsATransaction) {
// We dropped the whole transaction, the dropped count includes all child spans + 1 root
// span
[self recordLostSpanWithReason:kSentryDiscardReasonEventProcessor
quantity:currentSpanCount + 1];
}
} else {
if (eventIsATransactionClass) {
[self recordPartiallyDroppedSpans:(SentryTransaction *)event
withReason:kSentryDiscardReasonEventProcessor
withCurrentSpanCount:&currentSpanCount];
}
}

BOOL eventIsATransaction
= event.type != nil && [event.type isEqualToString:SentryEnvelopeItemTypeTransaction];
if (event != nil && eventIsATransaction && self.options.beforeSendSpan != nil) {
SentryTransaction *transaction = (SentryTransaction *)event;
NSMutableArray<id<SentrySpan>> *processedSpans = [NSMutableArray array];
Expand All @@ -735,15 +764,31 @@ - (SentryEvent *_Nullable)prepareEvent:(SentryEvent *)event
[processedSpans addObject:processedSpan];
}
}

transaction.spans = processedSpans;

if (eventIsATransactionClass) {
[self recordPartiallyDroppedSpans:transaction
withReason:kSentryDiscardReasonBeforeSend
withCurrentSpanCount:&currentSpanCount];
}
}

if (event != nil && nil != self.options.beforeSend) {
event = self.options.beforeSend(event);

if (event == nil) {
[self recordLost:eventIsNotATransaction reason:kSentryDiscardReasonBeforeSend];
if (eventIsATransaction) {
// We dropped the whole transaction, the dropped count includes all child spans + 1
// root span
[self recordLostSpanWithReason:kSentryDiscardReasonBeforeSend
quantity:currentSpanCount + 1];
}
} else {
if (eventIsATransactionClass) {
[self recordPartiallyDroppedSpans:(SentryTransaction *)event
withReason:kSentryDiscardReasonBeforeSend
withCurrentSpanCount:&currentSpanCount];
}
}
}

Expand All @@ -758,6 +803,19 @@ - (SentryEvent *_Nullable)prepareEvent:(SentryEvent *)event
return event;
}

- (void)recordPartiallyDroppedSpans:(SentryTransaction *)transaction
withReason:(SentryDiscardReason)reason
withCurrentSpanCount:(NSUInteger *)currentSpanCount
{
// If some spans got removed we still report them as dropped
NSUInteger spanCountAfter = transaction.spans.count;
NSUInteger droppedSpanCount = *currentSpanCount - spanCountAfter;
if (droppedSpanCount > 0) {
[self recordLostSpanWithReason:reason quantity:droppedSpanCount];
}
*currentSpanCount = spanCountAfter;
}

- (BOOL)isSampled:(NSNumber *)sampleRate
{
if (sampleRate == nil) {
Expand Down Expand Up @@ -971,6 +1029,11 @@ - (void)recordLost:(BOOL)eventIsNotATransaction reason:(SentryDiscardReason)reas
}
}

- (void)recordLostSpanWithReason:(SentryDiscardReason)reason quantity:(NSUInteger)quantity
{
[self recordLostEvent:kSentryDataCategorySpan reason:reason quantity:quantity];
}

- (void)addAttachmentProcessor:(id<SentryClientAttachmentProcessor>)attachmentProcessor
{
[self.attachmentProcessors addObject:attachmentProcessor];
Expand Down
7 changes: 7 additions & 0 deletions Sources/Sentry/SentryDataCategoryMapper.m
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
NSString *const kSentryDataCategoryNameProfileChunk = @"profile_chunk";
NSString *const kSentryDataCategoryNameReplay = @"replay";
NSString *const kSentryDataCategoryNameMetricBucket = @"metric_bucket";
NSString *const kSentryDataCategoryNameSpan = @"span";
NSString *const kSentryDataCategoryNameUnknown = @"unknown";

NS_ASSUME_NONNULL_BEGIN
Expand Down Expand Up @@ -47,6 +48,7 @@
if ([itemType isEqualToString:SentryEnvelopeItemTypeStatsd]) {
return kSentryDataCategoryMetricBucket;
}

return kSentryDataCategoryDefault;
}

Expand Down Expand Up @@ -96,6 +98,9 @@
if ([value isEqualToString:kSentryDataCategoryNameMetricBucket]) {
return kSentryDataCategoryMetricBucket;
}
if ([value isEqualToString:kSentryDataCategoryNameSpan]) {
return kSentryDataCategorySpan;
}

return kSentryDataCategoryUnknown;
}
Expand Down Expand Up @@ -132,6 +137,8 @@
return kSentryDataCategoryNameUnknown;
case kSentryDataCategoryReplay:
return kSentryDataCategoryNameReplay;
case kSentryDataCategorySpan:
return kSentryDataCategoryNameSpan;
}
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/Sentry/SentryEnvelopeRateLimit.m
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ - (SentryEnvelope *)removeRateLimitedItems:(SentryEnvelope *)envelope
= sentryDataCategoryForEnvelopItemType(item.header.type);
if ([self.rateLimits isRateLimitActive:rateLimitCategory]) {
[itemsToDrop addObject:item];
[self.delegate envelopeItemDropped:rateLimitCategory];
[self.delegate envelopeItemDropped:item withCategory:rateLimitCategory];
}
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/Sentry/SentryFileManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ - (void)handleEnvelopesLimit
continue;
}

[_delegate envelopeItemDeleted:rateLimitCategory];
[_delegate envelopeItemDeleted:item withCategory:rateLimitCategory];
}

[self removeFileAtPath:envelopeFilePath];
Expand Down
34 changes: 31 additions & 3 deletions Sources/Sentry/SentryHttpTransport.m
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#import "SentryHttpTransport.h"
#import "SentryClientReport.h"
#import "SentryDataCategory.h"
#import "SentryDataCategoryMapper.h"
#import "SentryDependencyContainer.h"
#import "SentryDiscardReasonMapper.h"
Expand Down Expand Up @@ -139,6 +140,13 @@
}

- (void)recordLostEvent:(SentryDataCategory)category reason:(SentryDiscardReason)reason
{
[self recordLostEvent:category reason:reason quantity:1];
}

- (void)recordLostEvent:(SentryDataCategory)category
reason:(SentryDiscardReason)reason
quantity:(NSUInteger)quantity
{
if (!self.options.sendClientReports) {
return;
Expand All @@ -149,7 +157,6 @@

@synchronized(self.discardedEvents) {
SentryDiscardedEvent *event = self.discardedEvents[key];
NSUInteger quantity = 1;
if (event != nil) {
quantity = event.quantity + 1;
}
Expand Down Expand Up @@ -225,17 +232,21 @@
/**
* SentryEnvelopeRateLimitDelegate.
*/
- (void)envelopeItemDropped:(SentryDataCategory)dataCategory
- (void)envelopeItemDropped:(SentryEnvelopeItem *)envelopeItem
withCategory:(SentryDataCategory)dataCategory;
{
[self recordLostEvent:dataCategory reason:kSentryDiscardReasonRateLimitBackoff];
[self recordLostSpans:envelopeItem reason:kSentryDiscardReasonRateLimitBackoff];
}

/**
* SentryFileManagerDelegate.
*/
- (void)envelopeItemDeleted:(SentryDataCategory)dataCategory
- (void)envelopeItemDeleted:(SentryEnvelopeItem *)envelopeItem
withCategory:(SentryDataCategory)dataCategory
{
[self recordLostEvent:dataCategory reason:kSentryDiscardReasonCacheOverflow];
[self recordLostSpans:envelopeItem reason:kSentryDiscardReasonCacheOverflow];
}

#pragma mark private methods
Expand Down Expand Up @@ -389,6 +400,23 @@
}
SentryDataCategory category = sentryDataCategoryForEnvelopItemType(itemType);
[self recordLostEvent:category reason:kSentryDiscardReasonNetworkError];
[self recordLostSpans:item reason:kSentryDiscardReasonNetworkError];
}
}

- (void)recordLostSpans:(SentryEnvelopeItem *)envelopeItem reason:(SentryDiscardReason)reason
{
if ([SentryEnvelopeItemTypeTransaction isEqualToString:envelopeItem.header.type]) {
NSDictionary *transactionJson =
[SentrySerialization deserializeEventEnvelopeItem:envelopeItem.data];
if (transactionJson == nil) {
return;

Check warning on line 413 in Sources/Sentry/SentryHttpTransport.m

View check run for this annotation

Codecov / codecov/patch

Sources/Sentry/SentryHttpTransport.m#L413

Added line #L413 was not covered by tests
}
NSArray *spans = transactionJson[@"spans"];
if (spans == nil) {
spans = [NSArray new];

Check warning on line 417 in Sources/Sentry/SentryHttpTransport.m

View check run for this annotation

Codecov / codecov/patch

Sources/Sentry/SentryHttpTransport.m#L417

Added line #L417 was not covered by tests
}
denrase marked this conversation as resolved.
Show resolved Hide resolved
[self recordLostEvent:kSentryDataCategorySpan reason:reason quantity:spans.count + 1];
}
}

Expand Down
3 changes: 3 additions & 0 deletions Sources/Sentry/SentryHub.m
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,9 @@ - (void)captureTransaction:(SentryTransaction *)transaction
if (decision != kSentrySampleDecisionYes) {
[self.client recordLostEvent:kSentryDataCategoryTransaction
reason:kSentryDiscardReasonSampleRate];
[self.client recordLostEvent:kSentryDataCategorySpan
reason:kSentryDiscardReasonSampleRate
quantity:transaction.spans.count + 1];
return;
}

Expand Down
8 changes: 8 additions & 0 deletions Sources/Sentry/SentrySpotlightTransport.m
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,19 @@ - (void)recordLostEvent:(SentryDataCategory)category reason:(SentryDiscardReason
// Empty on purpose
}

- (void)recordLostEvent:(SentryDataCategory)category
reason:(SentryDiscardReason)reason
quantity:(NSUInteger)quantity
{
// Empty on purpose
}

#if defined(TEST) || defined(TESTCI) || defined(DEBUG)
- (void)setStartFlushCallback:(nonnull void (^)(void))callback
{
// Empty on purpose
}

#endif // defined(TEST) || defined(TESTCI) || defined(DEBUG)

@end
Expand Down
9 changes: 9 additions & 0 deletions Sources/Sentry/SentryTransportAdapter.m
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,15 @@ - (void)recordLostEvent:(SentryDataCategory)category reason:(SentryDiscardReason
}
}

- (void)recordLostEvent:(SentryDataCategory)category
reason:(SentryDiscardReason)reason
quantity:(NSUInteger)quantity
{
for (id<SentryTransport> transport in self.transports) {
[transport recordLostEvent:category reason:reason quantity:quantity];
}
}

- (void)flush:(NSTimeInterval)timeout
{
for (id<SentryTransport> transport in self.transports) {
Expand Down
3 changes: 3 additions & 0 deletions Sources/Sentry/include/SentryClient+Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ SentryClient ()
- (void)captureEnvelope:(SentryEnvelope *)envelope;

- (void)recordLostEvent:(SentryDataCategory)category reason:(SentryDiscardReason)reason;
- (void)recordLostEvent:(SentryDataCategory)category
reason:(SentryDiscardReason)reason
quantity:(NSUInteger)quantity;

- (void)addAttachmentProcessor:(id<SentryClientAttachmentProcessor>)attachmentProcessor;
- (void)removeAttachmentProcessor:(id<SentryClientAttachmentProcessor>)attachmentProcessor;
Expand Down
3 changes: 2 additions & 1 deletion Sources/Sentry/include/SentryDataCategory.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ typedef NS_ENUM(NSUInteger, SentryDataCategory) {
kSentryDataCategoryMetricBucket = 8,
kSentryDataCategoryReplay = 9,
kSentryDataCategoryProfileChunk = 10,
kSentryDataCategoryUnknown = 11
kSentryDataCategorySpan = 11,
kSentryDataCategoryUnknown = 12,
};
1 change: 1 addition & 0 deletions Sources/Sentry/include/SentryDataCategoryMapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ FOUNDATION_EXPORT NSString *const kSentryDataCategoryNameProfile;
FOUNDATION_EXPORT NSString *const kSentryDataCategoryNameProfileChunk;
FOUNDATION_EXPORT NSString *const kSentryDataCategoryNameReplay;
FOUNDATION_EXPORT NSString *const kSentryDataCategoryNameMetricBucket;
FOUNDATION_EXPORT NSString *const kSentryDataCategoryNameSpan;
FOUNDATION_EXPORT NSString *const kSentryDataCategoryNameUnknown;

SentryDataCategory sentryDataCategoryForNSUInteger(NSUInteger value);
Expand Down
5 changes: 3 additions & 2 deletions Sources/Sentry/include/SentryEnvelopeRateLimit.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

@protocol SentryEnvelopeRateLimitDelegate;

@class SentryEnvelope;
@class SentryEnvelope, SentryEnvelopeItem;

NS_ASSUME_NONNULL_BEGIN

Expand All @@ -23,7 +23,8 @@ NS_SWIFT_NAME(EnvelopeRateLimit)

@protocol SentryEnvelopeRateLimitDelegate <NSObject>

- (void)envelopeItemDropped:(SentryDataCategory)dataCategory;
- (void)envelopeItemDropped:(SentryEnvelopeItem *)envelopeItem
withCategory:(SentryDataCategory)dataCategory;

@end

Expand Down
Loading
Loading