Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
1bb772c
Mark exceptions not handled by user as `handled: false` (#1535)
denrase Jul 27, 2023
3d1d35b
Refrain from overwriting the span status for unfinished spans (#1577)
denrase Aug 22, 2023
380c28a
Merge branch 'main' into release/8.0.0
denrase Aug 29, 2023
852a85e
update changelog
denrase Aug 29, 2023
c59de47
Do not leak extensions of external classes (#1576)
denrase Sep 4, 2023
052a368
Make `hint` non-nullable in `BeforeSendCallback`, `BeforeBreadcrumbCa…
denrase Sep 4, 2023
a37a793
Load Device Contexts from Sentry Java (#1616)
denrase Sep 11, 2023
9b28718
Set ip_address to {{auto}} by default, even if sendDefaultPII is disa…
denrase Oct 9, 2023
d99a1e4
chore: merge main into v8 branch (#1841)
buenaflor Jan 31, 2024
fab52eb
chore(v8): update to min ios version 12 (#1821)
buenaflor Jan 31, 2024
0fb55cf
v8 prep: merge main into 8.0.0 branch (#1871)
buenaflor Feb 7, 2024
5481ba1
Merge branch 'main' into release/8.0.0
buenaflor Feb 8, 2024
90c63b9
release: 8.0.0-beta.2
getsentry-bot Feb 8, 2024
89c8e41
Update CHANGELOG
buenaflor Feb 8, 2024
8166d0c
Merge branch 'release/8.0.0-beta.2' into release/8.0.0
Feb 9, 2024
6075021
Testflight (#1938)
denrase Apr 10, 2024
94ff648
Merge branch 'main' into release/8.0.0
buenaflor Apr 18, 2024
5539fed
Merge branch 'main' into release/8.0.0
buenaflor Apr 18, 2024
07d34a8
Fix test compilation
buenaflor Apr 18, 2024
4a762db
Update CHANGELOG.md
buenaflor Apr 18, 2024
e74ea75
Update CHANGELOG.md
buenaflor Apr 18, 2024
06368d6
Update CHANGELOG.md
buenaflor Apr 18, 2024
086d66e
Fix analyze issues
buenaflor Apr 18, 2024
621807f
Apply formatter
buenaflor Apr 18, 2024
3af8df8
Update versions to 8.0.0 (#1996)
buenaflor Apr 18, 2024
645aefa
Fix compilation
buenaflor Apr 18, 2024
9acd049
Exception aggregate mechanism (#1866)
ueman Apr 18, 2024
5d2ff07
Update CHANGELOG.md
buenaflor Apr 18, 2024
5264e78
Update CHANGELOG
buenaflor Apr 19, 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
Prev Previous commit
Next Next commit
Load Device Contexts from Sentry Java (#1616)
  • Loading branch information
denrase authored Sep 11, 2023
commit a37a79355f5592d9ec64a77b5e51763fabdf2c27
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
- Do not leak extensions of external classes ([#1576](https://github.com/getsentry/sentry-dart/pull/1576))
- Make `hint` non-nullable in `BeforeSendCallback`, `BeforeBreadcrumbCall` and `EventProcessor` ([#1574](https://github.com/getsentry/sentry-dart/pull/1574))
- This will affect your callbacks, making this a breaking change.

- Load Device Contexts from Sentry Java ([#1616](https://github.com/getsentry/sentry-dart/pull/1616))
- Now the device context from Android is available in `BeforeSendCallback`

## Unreleased

### Fixes
Expand Down
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 @@ -322,8 +320,6 @@ class SentryClient {
return _sentryId;
}

preparedTransaction = _eventWithoutBreadcrumbsIfNeeded(preparedTransaction);

final attachments = scope?.attachments
.where((element) => element.addToTransactions)
.toList();
Expand Down Expand Up @@ -457,40 +453,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 @@ -1153,201 +1153,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
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import io.sentry.SentryOptions
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
Expand Down Expand Up @@ -65,6 +66,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 @@ -94,18 +96,6 @@ class SentryFlutterPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
// Stub
}

private fun writeEnvelope(envelope: ByteArray): Boolean {
val options = HubAdapter.getInstance().options
if (options.outboxPath.isNullOrEmpty()) {
return false
}

val file = File(options.outboxPath, UUID.randomUUID().toString())
file.writeBytes(envelope)

return true
}

private fun initNativeSdk(call: MethodCall, result: Result) {
if (!this::context.isInitialized) {
result.error("1", "Context is null", null)
Expand Down Expand Up @@ -356,20 +346,19 @@ class SentryFlutterPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
result.error("1", "The Sentry Android SDK is disabled", null)
return
}

val args = call.arguments() as List<Any>? ?: listOf<Any>()
val args = call.arguments() as List<Any>? ?: listOf()
if (args.isNotEmpty()) {
val event = args.first() as ByteArray?

if (event != null && event.isNotEmpty()) {
if (!writeEnvelope(event)) {
result.error("2", "SentryOptions or outboxPath are null or empty", null)
val id = InternalSentrySdk.captureEnvelope(event)
if (id != null) {
result.success("")
} else {
result.error("2", "Failed to capture envelope", null)
}
result.success("")
return
}
}

result.error("3", "Envelope is null or empty", null)
}

Expand Down Expand Up @@ -454,6 +443,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
17 changes: 6 additions & 11 deletions flutter/lib/src/integrations/load_contexts_integration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,16 @@ import 'package:flutter/services.dart';
import 'package:sentry/sentry.dart';
import '../sentry_flutter_options.dart';

/// Load Device's Contexts from the iOS SDK.
/// Load Device's Contexts from the iOS & Android SDKs.
///
/// This integration calls the iOS SDK via Message channel to load the
/// Device's contexts before sending the event back to the iOS SDK via
/// This integration calls the iOS & Android SDKs via Message channel to load
/// the Device's contexts before sending the event back to the SDK via
/// Message channel (already enriched with all the information).
///
/// The Device's contexts are:
/// App, Device and OS.
///
/// ps. This integration won't be run on Android because the Device's Contexts
/// is set on Android when the event is sent to the Android SDK via
/// the Message channel.
/// We intend to unify this behaviour in the future.
///
/// This integration is only executed on iOS & MacOS Apps.
/// This integration is only executed on iOS, macOS & Android Apps.
class LoadContextsIntegration extends Integration<SentryFlutterOptions> {
final MethodChannel _channel;

Expand Down Expand Up @@ -194,8 +189,8 @@ class _LoadContextsIntegrationEventProcessor implements EventProcessor {
event = event.copyWith(sdk: sdk);
}

// on iOS, captureEnvelope does not call the beforeSend callback,
// hence we need to add these tags here.
// captureEnvelope does not call the beforeSend callback, hence we need to
// add these tags here.
if (event.sdk?.name == 'sentry.dart.flutter') {
final tags = event.tags ?? {};
tags['event.origin'] = 'flutter';
Expand Down
Loading