Skip to content

Commit 0ac1eed

Browse files
authored
Remove breadcrumbs from transaction to avoid duplication (#1366)
1 parent b9da046 commit 0ac1eed

File tree

3 files changed

+55
-24
lines changed

3 files changed

+55
-24
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
- Fix Dart web builds breaking due to `dart:io` imports when using `SentryIsolate` or `SentryIsolateExtension` ([#1371](https://github.com/getsentry/sentry-dart/pull/1371))
88
- When using `SentryIsolate` or `SentryIsolateExtension`, import `sentry_io.dart`.
9+
- Remove breadcrumbs from transaction to avoid duplication ([#1366](https://github.com/getsentry/sentry-dart/pull/1366))
910

1011
## 7.4.0
1112

dart/lib/src/sentry_client.dart

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -108,18 +108,7 @@ class SentryClient {
108108
return _sentryId;
109109
}
110110

111-
if (_options.platformChecker.platform.isAndroid &&
112-
_options.enableScopeSync) {
113-
/*
114-
We do this to avoid duplicate breadcrumbs on Android as sentry-android applies the breadcrumbs
115-
from the native scope onto every envelope sent through it. This scope will contain the breadcrumbs
116-
sent through the scope sync feature. This causes duplicate breadcrumbs.
117-
We then remove the breadcrumbs in all cases but if it is handled == false,
118-
this is a signal that the app would crash and android would lose the breadcrumbs by the time the app is restarted to read
119-
the envelope.
120-
*/
121-
preparedEvent = _eventWithRemovedBreadcrumbsIfHandled(preparedEvent);
122-
}
111+
preparedEvent = _eventWithoutBreadcrumbsIfNeeded(preparedEvent);
123112

124113
var attachments = List<SentryAttachment>.from(scope?.attachments ?? []);
125114
var screenshot = hint.screenshot;
@@ -329,6 +318,8 @@ class SentryClient {
329318
return _sentryId;
330319
}
331320

321+
preparedTransaction = _eventWithoutBreadcrumbsIfNeeded(preparedTransaction);
322+
332323
final attachments = scope?.attachments
333324
.where((element) => element.addToTransactions)
334325
.toList();
@@ -462,18 +453,34 @@ class SentryClient {
462453
_options.recorder.recordLostEvent(reason, category);
463454
}
464455

465-
SentryEvent _eventWithRemovedBreadcrumbsIfHandled(SentryEvent event) {
456+
T _eventWithoutBreadcrumbsIfNeeded<T extends SentryEvent>(T event) {
457+
if (_shouldRemoveBreadcrumbs(event)) {
458+
return event.copyWith(breadcrumbs: []) as T;
459+
} else {
460+
return event;
461+
}
462+
}
463+
464+
/// We do this to avoid duplicate breadcrumbs on Android as sentry-android applies the breadcrumbs
465+
/// from the native scope onto every envelope sent through it. This scope will contain the breadcrumbs
466+
/// sent through the scope sync feature. This causes duplicate breadcrumbs.
467+
/// We then remove the breadcrumbs in all cases but if it is handled == false,
468+
/// this is a signal that the app would crash and android would lose the breadcrumbs by the time the app is restarted to read
469+
/// the envelope.
470+
bool _shouldRemoveBreadcrumbs(SentryEvent event) {
471+
final isAndroid = _options.platformChecker.platform.isAndroid;
472+
final enableScopeSync = _options.enableScopeSync;
473+
474+
if (!isAndroid || !enableScopeSync) {
475+
return false;
476+
}
477+
466478
final mechanisms =
467479
(event.exceptions ?? []).map((e) => e.mechanism).whereType<Mechanism>();
468480
final hasNoMechanism = mechanisms.isEmpty;
469481
final hasOnlyHandledMechanism =
470482
mechanisms.every((e) => (e.handled ?? true));
471-
472-
if (hasNoMechanism || hasOnlyHandledMechanism) {
473-
return event.copyWith(breadcrumbs: []);
474-
} else {
475-
return event;
476-
}
483+
return hasNoMechanism || hasOnlyHandledMechanism;
477484
}
478485

479486
Future<SentryId?> _attachClientReportsAndSend(SentryEnvelope envelope) {

dart/test/sentry_client_test.dart

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,7 +1154,28 @@ void main() {
11541154
fixture = Fixture();
11551155
});
11561156

1157-
test('Clears breadcrumbs on Android if mechanism.handled is true',
1157+
test('Clears breadcrumbs on Android for transaction', () async {
1158+
fixture.options.enableScopeSync = true;
1159+
fixture.options.platformChecker =
1160+
MockPlatformChecker(platform: MockPlatform.android());
1161+
1162+
final client = fixture.getSut();
1163+
final transaction = SentryTransaction(
1164+
fixture.tracer,
1165+
breadcrumbs: [
1166+
Breadcrumb(),
1167+
],
1168+
);
1169+
await client.captureTransaction(transaction);
1170+
1171+
final capturedEnvelope = (fixture.transport).envelopes.first;
1172+
final capturedTransaction =
1173+
await transactionFromEnvelope(capturedEnvelope);
1174+
1175+
expect((capturedTransaction['breadcrumbs'] ?? []).isEmpty, true);
1176+
});
1177+
1178+
test('Clears breadcrumbs on Android if mechanism.handled is true for event',
11581179
() async {
11591180
fixture.options.enableScopeSync = true;
11601181
fixture.options.platformChecker =
@@ -1181,7 +1202,7 @@ void main() {
11811202
expect((capturedEvent.breadcrumbs ?? []).isEmpty, true);
11821203
});
11831204

1184-
test('Clears breadcrumbs on Android if mechanism.handled is null',
1205+
test('Clears breadcrumbs on Android if mechanism.handled is null for event',
11851206
() async {
11861207
fixture.options.enableScopeSync = true;
11871208
fixture.options.platformChecker =
@@ -1205,7 +1226,8 @@ void main() {
12051226
expect((capturedEvent.breadcrumbs ?? []).isEmpty, true);
12061227
});
12071228

1208-
test('Clears breadcrumbs on Android if theres no mechanism', () async {
1229+
test('Clears breadcrumbs on Android if theres no mechanism for event',
1230+
() async {
12091231
fixture.options.enableScopeSync = true;
12101232
fixture.options.platformChecker =
12111233
MockPlatformChecker(platform: MockPlatform.android());
@@ -1227,7 +1249,8 @@ void main() {
12271249
expect((capturedEvent.breadcrumbs ?? []).isEmpty, true);
12281250
});
12291251

1230-
test('Does not clear breadcrumbs on Android if mechanism.handled is false',
1252+
test(
1253+
'Does not clear breadcrumbs on Android if mechanism.handled is false for event',
12311254
() async {
12321255
fixture.options.enableScopeSync = true;
12331256
fixture.options.platformChecker =
@@ -1255,7 +1278,7 @@ void main() {
12551278
});
12561279

12571280
test(
1258-
'Does not clear breadcrumbs on Android if any mechanism.handled is false',
1281+
'Does not clear breadcrumbs on Android if any mechanism.handled is false for event',
12591282
() async {
12601283
fixture.options.enableScopeSync = true;
12611284
fixture.options.platformChecker =

0 commit comments

Comments
 (0)