Skip to content

Commit

Permalink
Merge branch 'main' into feat/report-dropped-spans
Browse files Browse the repository at this point in the history
  • Loading branch information
buenaflor authored Jul 9, 2024
2 parents 8ad162f + 3d305b9 commit d8744bf
Show file tree
Hide file tree
Showing 11 changed files with 102 additions and 15 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
- Bump Cocoa SDK from v8.29.0 to v8.30.0 ([#2132](https://github.com/getsentry/sentry-dart/pull/2132))
- [changelog](https://github.com/getsentry/sentry-cocoa/blob/main/CHANGELOG.md#8300)
- [diff](https://github.com/getsentry/sentry-cocoa/compare/8.29.0...8.30.0)
- Bump Android SDK from v7.10.0 to v7.11.0 ([#2144](https://github.com/getsentry/sentry-dart/pull/2144))
- [changelog](https://github.com/getsentry/sentry-java/blob/main/CHANGELOG.md#7110)
- [diff](https://github.com/getsentry/sentry-java/compare/7.10.0...7.11.0)

## 8.3.0

Expand Down
17 changes: 16 additions & 1 deletion dart/lib/src/sentry_envelope.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,19 @@ import 'sentry_user_feedback.dart';

/// Class representation of `Envelope` file.
class SentryEnvelope {
SentryEnvelope(this.header, this.items);
SentryEnvelope(this.header, this.items,
{this.containsUnhandledException = false});

/// Header describing envelope content.
final SentryEnvelopeHeader header;

/// All items contained in the envelope.
final List<SentryEnvelopeItem> items;

/// Whether the envelope contains an unhandled exception.
/// This is used to determine if the native SDK should start a new session.
final bool containsUnhandledException;

/// Create a [SentryEnvelope] containing one [SentryEnvelopeItem] which holds the [SentryEvent] data.
factory SentryEnvelope.fromEvent(
SentryEvent event,
Expand All @@ -29,6 +34,15 @@ class SentryEnvelope {
SentryTraceContextHeader? traceContext,
List<SentryAttachment>? attachments,
}) {
bool containsUnhandledException = false;

if (event.exceptions != null && event.exceptions!.isNotEmpty) {
// Check all exceptions for any unhandled ones
containsUnhandledException = event.exceptions!.any((exception) {
return exception.mechanism?.handled == false;
});
}

return SentryEnvelope(
SentryEnvelopeHeader(
event.eventId,
Expand All @@ -41,6 +55,7 @@ class SentryEnvelope {
if (attachments != null)
...attachments.map((e) => SentryEnvelopeItem.fromAttachment(e))
],
containsUnhandledException: containsUnhandledException,
);
}

Expand Down
3 changes: 3 additions & 0 deletions dart/test/mocks/mock_envelope.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,7 @@ class MockEnvelope implements SentryEnvelope {

@override
List<SentryEnvelopeItem> items = [];

@override
bool get containsUnhandledException => false;
}
2 changes: 1 addition & 1 deletion flutter/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ android {
}

dependencies {
api 'io.sentry:sentry-android:7.10.0'
api 'io.sentry:sentry-android:7.11.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"

// Required -- JUnit 4 framework
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -355,8 +355,9 @@ class SentryFlutterPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
val args = call.arguments() as List<Any>? ?: listOf()
if (args.isNotEmpty()) {
val event = args.first() as ByteArray?
if (event != null && event.isNotEmpty()) {
val id = InternalSentrySdk.captureEnvelope(event)
val containsUnhandledException = args[1] as Boolean
if (event != null && event.isNotEmpty() && containsUnhandledException != null) {
val id = InternalSentrySdk.captureEnvelope(event, containsUnhandledException)
if (id != null) {
result.success("")
} else {
Expand Down
3 changes: 2 additions & 1 deletion flutter/lib/src/file_system_transport.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ class FileSystemTransport implements Transport {
await envelope.envelopeStream(_options).forEach(envelopeData.addAll);
try {
// TODO avoid copy
await _native.captureEnvelope(Uint8List.fromList(envelopeData));
await _native.captureEnvelope(Uint8List.fromList(envelopeData),
envelope.containsUnhandledException);
} catch (exception, stackTrace) {
_options.logger(
SentryLevel.error,
Expand Down
3 changes: 2 additions & 1 deletion flutter/lib/src/native/sentry_native_binding.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ abstract class SentryNativeBinding {

Future<NativeAppStart?> fetchNativeAppStart();

Future<void> captureEnvelope(Uint8List envelopeData);
Future<void> captureEnvelope(
Uint8List envelopeData, bool containsUnhandledException);

Future<void> beginNativeFrames();

Expand Down
7 changes: 5 additions & 2 deletions flutter/lib/src/native/sentry_native_channel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,11 @@ class SentryNativeChannel
}

@override
Future<void> captureEnvelope(Uint8List envelopeData) =>
_channel.invokeMethod('captureEnvelope', [envelopeData]);
Future<void> captureEnvelope(
Uint8List envelopeData, bool containsUnhandledException) {
return _channel.invokeMethod(
'captureEnvelope', [envelopeData, containsUnhandledException]);
}

@override
Future<Map<String, dynamic>?> loadContexts() =>
Expand Down
62 changes: 58 additions & 4 deletions flutter/test/file_system_transport_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
library flutter_test;

import 'dart:convert';

// backcompatibility for Flutter < 3.3
// ignore: unnecessary_import
import 'dart:typed_data';
Expand Down Expand Up @@ -39,7 +40,7 @@ void main() {
});

test('$FileSystemTransport returns emptyId if channel throws', () async {
when(fixture.binding.captureEnvelope(any)).thenThrow(Exception());
when(fixture.binding.captureEnvelope(any, false)).thenThrow(Exception());

final transport = fixture.getSut();
final event = SentryEvent();
Expand All @@ -56,6 +57,58 @@ void main() {
expect(SentryId.empty(), sentryId);
});

test(
'sets unhandled exception flag in captureEnvelope to true for unhandled exception',
() async {
final transport = fixture.getSut();

final unhandledException = SentryException(
mechanism: Mechanism(type: 'UnhandledException', handled: false),
threadId: 99,
type: 'Exception',
value: 'Unhandled exception',
);
final event = SentryEvent(exceptions: [unhandledException]);
final sdkVersion =
SdkVersion(name: 'fixture-sdkName', version: 'fixture-sdkVersion');
final envelope = SentryEnvelope.fromEvent(
event,
sdkVersion,
dsn: fixture.options.dsn,
);

await transport.send(envelope);

verify(fixture.binding.captureEnvelope(captureAny, true)).captured.single
as Uint8List;
});

test(
'sets unhandled exception flag in captureEnvelope to false for handled exception',
() async {
final transport = fixture.getSut();

final unhandledException = SentryException(
mechanism: Mechanism(type: 'UnhandledException', handled: true),
threadId: 99,
type: 'Exception',
value: 'Unhandled exception',
);
final event = SentryEvent(exceptions: [unhandledException]);
final sdkVersion =
SdkVersion(name: 'fixture-sdkName', version: 'fixture-sdkVersion');
final envelope = SentryEnvelope.fromEvent(
event,
sdkVersion,
dsn: fixture.options.dsn,
);

await transport.send(envelope);

verify(fixture.binding.captureEnvelope(captureAny, false)).captured.single
as Uint8List;
});

test('$FileSystemTransport asserts the event', () async {
final transport = fixture.getSut();

Expand All @@ -70,9 +123,10 @@ void main() {
);
await transport.send(envelope);

final envelopeData = verify(fixture.binding.captureEnvelope(captureAny))
.captured
.single as Uint8List;
final envelopeData =
verify(fixture.binding.captureEnvelope(captureAny, false))
.captured
.single as Uint8List;
final envelopeString = utf8.decode(envelopeData);
final lines = envelopeString.split('\n');
final envelopeHeader = lines.first;
Expand Down
10 changes: 8 additions & 2 deletions flutter/test/mocks.mocks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1116,11 +1116,17 @@ class MockSentryNativeBinding extends _i1.Mock
) as _i8.Future<_i15.NativeAppStart?>);

@override
_i8.Future<void> captureEnvelope(_i16.Uint8List? envelopeData) =>
_i8.Future<void> captureEnvelope(
_i16.Uint8List? envelopeData,
bool? containsUnhandledException,
) =>
(super.noSuchMethod(
Invocation.method(
#captureEnvelope,
[envelopeData],
[
envelopeData,
containsUnhandledException,
],
),
returnValue: _i8.Future<void>.value(),
returnValueForMissingStub: _i8.Future<void>.value(),
Expand Down
2 changes: 1 addition & 1 deletion flutter/test/sentry_native_channel_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ void main() {
(invocation) async =>
{captured = invocation.positionalArguments[1][0] as Uint8List});

await sut.captureEnvelope(data);
await sut.captureEnvelope(data, false);

expect(captured, data);
});
Expand Down

0 comments on commit d8744bf

Please sign in to comment.