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

Load Device Contexts from Sentry Java #1616

Merged
merged 12 commits into from
Sep 11, 2023
38 changes: 0 additions & 38 deletions dart/lib/src/sentry_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,6 @@ class SentryClient {
return _sentryId;
}

preparedEvent = _eventWithoutBreadcrumbsIfNeeded(preparedEvent);

var attachments = List<SentryAttachment>.from(scope?.attachments ?? []);
attachments.addAll(hint.attachments);
var screenshot = hint.screenshot;
Expand Down Expand Up @@ -319,8 +317,6 @@ class SentryClient {
return _sentryId;
}

preparedTransaction = _eventWithoutBreadcrumbsIfNeeded(preparedTransaction);

final attachments = scope?.attachments
.where((element) => element.addToTransactions)
.toList();
Expand Down Expand Up @@ -454,40 +450,6 @@ class SentryClient {
_options.recorder.recordLostEvent(reason, category);
}

T _eventWithoutBreadcrumbsIfNeeded<T extends SentryEvent>(T event) {
if (_shouldRemoveBreadcrumbs(event)) {
return event.copyWith(breadcrumbs: []) as T;
} else {
return event;
}
}

/// We do this to avoid duplicate breadcrumbs on Android as sentry-android applies the breadcrumbs
/// from the native scope onto every envelope sent through it. This scope will contain the breadcrumbs
/// sent through the scope sync feature. This causes duplicate breadcrumbs.
/// We then remove the breadcrumbs in all cases but if it is handled == false,
/// this is a signal that the app would crash and android would lose the breadcrumbs by the time the app is restarted to read
/// the envelope.
bool _shouldRemoveBreadcrumbs(SentryEvent event) {
if (_options.platformChecker.isWeb) {
return false;
}

final isAndroid = _options.platformChecker.platform.isAndroid;
final enableScopeSync = _options.enableScopeSync;

if (!isAndroid || !enableScopeSync) {
return false;
}

final mechanisms =
(event.exceptions ?? []).map((e) => e.mechanism).whereType<Mechanism>();
final hasNoMechanism = mechanisms.isEmpty;
final hasOnlyHandledMechanism =
mechanisms.every((e) => (e.handled ?? true));
return hasNoMechanism || hasOnlyHandledMechanism;
}

Future<SentryId?> _attachClientReportsAndSend(SentryEnvelope envelope) {
final clientReport = _options.recorder.flush();
envelope.addClientReport(clientReport);
Expand Down
195 changes: 0 additions & 195 deletions dart/test/sentry_client_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1152,201 +1152,6 @@ void main() {
});
});

group('Breadcrumbs', () {
late Fixture fixture;

setUp(() {
fixture = Fixture();
});

test('Clears breadcrumbs on Android for transaction', () async {
fixture.options.enableScopeSync = true;
fixture.options.platformChecker =
MockPlatformChecker(platform: MockPlatform.android());

final client = fixture.getSut();
final transaction = SentryTransaction(
fixture.tracer,
breadcrumbs: [
Breadcrumb(),
],
);
await client.captureTransaction(transaction);

final capturedEnvelope = (fixture.transport).envelopes.first;
final capturedTransaction =
await transactionFromEnvelope(capturedEnvelope);

expect((capturedTransaction['breadcrumbs'] ?? []).isEmpty, true);
});

test('Clears breadcrumbs on Android if mechanism.handled is true for event',
() async {
fixture.options.enableScopeSync = true;
fixture.options.platformChecker =
MockPlatformChecker(platform: MockPlatform.android());

final client = fixture.getSut();
final event = SentryEvent(exceptions: [
SentryException(
type: "type",
value: "value",
mechanism: Mechanism(
type: 'type',
handled: true,
),
)
], breadcrumbs: [
Breadcrumb()
]);
await client.captureEvent(event);

final capturedEnvelope = (fixture.transport).envelopes.first;
final capturedEvent = await eventFromEnvelope(capturedEnvelope);

expect((capturedEvent.breadcrumbs ?? []).isEmpty, true);
});

test('Clears breadcrumbs on Android if mechanism.handled is null for event',
() async {
fixture.options.enableScopeSync = true;
fixture.options.platformChecker =
MockPlatformChecker(platform: MockPlatform.android());

final client = fixture.getSut();
final event = SentryEvent(exceptions: [
SentryException(
type: "type",
value: "value",
mechanism: Mechanism(type: 'type'),
)
], breadcrumbs: [
Breadcrumb()
]);
await client.captureEvent(event);

final capturedEnvelope = (fixture.transport).envelopes.first;
final capturedEvent = await eventFromEnvelope(capturedEnvelope);

expect((capturedEvent.breadcrumbs ?? []).isEmpty, true);
});

test('Clears breadcrumbs on Android if theres no mechanism for event',
() async {
fixture.options.enableScopeSync = true;
fixture.options.platformChecker =
MockPlatformChecker(platform: MockPlatform.android());

final client = fixture.getSut();
final event = SentryEvent(exceptions: [
SentryException(
type: "type",
value: "value",
)
], breadcrumbs: [
Breadcrumb()
]);
await client.captureEvent(event);

final capturedEnvelope = (fixture.transport).envelopes.first;
final capturedEvent = await eventFromEnvelope(capturedEnvelope);

expect((capturedEvent.breadcrumbs ?? []).isEmpty, true);
});

test(
'Does not clear breadcrumbs on Android if mechanism.handled is false for event',
() async {
fixture.options.enableScopeSync = true;
fixture.options.platformChecker =
MockPlatformChecker(platform: MockPlatform.android());

final client = fixture.getSut();
final event = SentryEvent(exceptions: [
SentryException(
type: "type",
value: "value",
mechanism: Mechanism(
type: 'type',
handled: false,
),
)
], breadcrumbs: [
Breadcrumb()
]);
await client.captureEvent(event);

final capturedEnvelope = (fixture.transport).envelopes.first;
final capturedEvent = await eventFromEnvelope(capturedEnvelope);

expect((capturedEvent.breadcrumbs ?? []).isNotEmpty, true);
});

test(
'Does not clear breadcrumbs on Android if any mechanism.handled is false for event',
() async {
fixture.options.enableScopeSync = true;
fixture.options.platformChecker =
MockPlatformChecker(platform: MockPlatform.android());

final client = fixture.getSut();
final event = SentryEvent(exceptions: [
SentryException(
type: "type",
value: "value",
mechanism: Mechanism(
type: 'type',
handled: true,
),
),
SentryException(
type: "type",
value: "value",
mechanism: Mechanism(
type: 'type',
handled: false,
),
)
], breadcrumbs: [
Breadcrumb()
]);
await client.captureEvent(event);

final capturedEnvelope = (fixture.transport).envelopes.first;
final capturedEvent = await eventFromEnvelope(capturedEnvelope);

expect((capturedEvent.breadcrumbs ?? []).isNotEmpty, true);
});

test('web breadcrumbs exist on web Android devices', () async {
fixture.options.enableScopeSync = true;
fixture.options.platformChecker = MockPlatformChecker(
platform: MockPlatform.android(),
isWebValue: true,
);

final client = fixture.getSut();
final event = SentryEvent(exceptions: [
SentryException(
type: "type",
value: "value",
mechanism: Mechanism(
type: 'type',
handled: true,
),
),
], breadcrumbs: [
Breadcrumb(),
]);
await client.captureEvent(event);

final capturedEnvelope = (fixture.transport).envelopes.first;
final capturedEvent = await eventFromEnvelope(capturedEnvelope);

expect((capturedEvent.breadcrumbs ?? []).isNotEmpty, true);
});
});

group('ClientReportRecorder', () {
late Fixture fixture;

Expand Down
2 changes: 1 addition & 1 deletion flutter/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,6 @@ android {
}

dependencies {
api 'io.sentry:sentry-android:6.25.2'
api 'io.sentry:sentry-android:6.28.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,25 @@ import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.plugin.common.StandardMessageCodec
denrase marked this conversation as resolved.
Show resolved Hide resolved
import io.sentry.Breadcrumb
import io.sentry.DateUtils
import io.sentry.HubAdapter
import io.sentry.Scope
denrase marked this conversation as resolved.
Show resolved Hide resolved
import io.sentry.Sentry
import io.sentry.SentryEvent
import io.sentry.SentryLevel
import io.sentry.Sentry
import io.sentry.DateUtils
import io.sentry.android.core.ActivityFramesTracker
import io.sentry.android.core.AppStartState
import io.sentry.android.core.BuildConfig.VERSION_NAME
import io.sentry.android.core.InternalSentrySdk
import io.sentry.android.core.LoadClass
import io.sentry.android.core.SentryAndroid
import io.sentry.android.core.SentryAndroidOptions
import io.sentry.protocol.DebugImage
import io.sentry.protocol.SdkVersion
import io.sentry.protocol.SentryId
import io.sentry.protocol.User
import io.sentry.protocol.Geo
import java.io.File
import java.lang.ref.WeakReference
import java.util.Locale
Expand Down Expand Up @@ -68,6 +70,7 @@ class SentryFlutterPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
"removeExtra" -> removeExtra(call.argument("key"), result)
"setTag" -> setTag(call.argument("key"), call.argument("value"), result)
"removeTag" -> removeTag(call.argument("key"), result)
"loadContexts" -> loadContexts(result)
else -> result.notImplemented()
}
}
Expand Down Expand Up @@ -436,6 +439,21 @@ class SentryFlutterPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
}
}
}

private fun loadContexts(result: Result) {
val options = HubAdapter.getInstance().options
if (options !is SentryAndroidOptions) {
result.success(null)
return
}
val currentScope = InternalSentrySdk.getCurrentScope()
val serializedScope = InternalSentrySdk.serializeScope(
context,
options,
currentScope
)
result.success(serializedScope)
}
}

// Call the `completion` closure if cast to map value with `key` and type `T` is successful.
Expand Down
2 changes: 1 addition & 1 deletion flutter/lib/src/sentry_flutter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ mixin SentryFlutter {
// Will enrich events with device context, native packages and integrations
if (platformChecker.hasNativeIntegration &&
!platformChecker.isWeb &&
(platform.isIOS || platform.isMacOS)) {
(platform.isIOS || platform.isMacOS || platform.isAndroid)) {
integrations.add(LoadContextsIntegration(channel));
}

Expand Down