diff --git a/CHANGELOG.md b/CHANGELOG.md index 23aef939fe..1abf8b80a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Add http.request.method attribute to http spans data ([#1633](https://github.com/getsentry/sentry-dart/pull/1633)) - Add db.system and db.name attributes to db spans data ([#1629](https://github.com/getsentry/sentry-dart/pull/1629)) +- Log SDK errors to the console if the log level is `fatal` even if `debug` is disabled ([#1635](https://github.com/getsentry/sentry-dart/pull/1635)) ### Features diff --git a/dart/lib/src/diagnostic_logger.dart b/dart/lib/src/diagnostic_logger.dart index 9a393f974f..ca523c12ae 100644 --- a/dart/lib/src/diagnostic_logger.dart +++ b/dart/lib/src/diagnostic_logger.dart @@ -26,6 +26,8 @@ class DiagnosticLogger { } bool _isEnabled(SentryLevel level) { - return _options.debug && level.ordinal >= _options.diagnosticLevel.ordinal; + return _options.debug && + level.ordinal >= _options.diagnosticLevel.ordinal || + level == SentryLevel.fatal; } } diff --git a/dart/test/diagnostic_logger_test.dart b/dart/test/diagnostic_logger_test.dart new file mode 100644 index 0000000000..ec53421e33 --- /dev/null +++ b/dart/test/diagnostic_logger_test.dart @@ -0,0 +1,64 @@ +import 'package:sentry/sentry.dart'; +import 'package:sentry/src/diagnostic_logger.dart'; +import 'package:test/test.dart'; + +void main() { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + test('$DiagnosticLogger do not log if debug is disabled', () { + fixture.options.debug = false; + + fixture.getSut().log(SentryLevel.error, 'foobar'); + + expect(fixture.loggedMessage, isNull); + }); + + test('$DiagnosticLogger log if debug is enabled', () { + fixture.options.debug = true; + + fixture.getSut().log(SentryLevel.error, 'foobar'); + + expect(fixture.loggedMessage, 'foobar'); + }); + + test('$DiagnosticLogger do not log if level is too low', () { + fixture.options.debug = true; + fixture.options.diagnosticLevel = SentryLevel.error; + + fixture.getSut().log(SentryLevel.warning, 'foobar'); + + expect(fixture.loggedMessage, isNull); + }); + + test('$DiagnosticLogger always log fatal', () { + fixture.options.debug = false; + + fixture.getSut().log(SentryLevel.fatal, 'foobar'); + + expect(fixture.loggedMessage, 'foobar'); + }); +} + +class Fixture { + var options = SentryOptions(); + + Object? loggedMessage; + + DiagnosticLogger getSut() { + return DiagnosticLogger(mockLogger, options); + } + + void mockLogger( + SentryLevel level, + String message, { + String? logger, + Object? exception, + StackTrace? stackTrace, + }) { + loggedMessage = message; + } +} diff --git a/flutter/analysis_options.yaml b/flutter/analysis_options.yaml index 47255eaaa4..d95702842f 100644 --- a/flutter/analysis_options.yaml +++ b/flutter/analysis_options.yaml @@ -1,6 +1,8 @@ include: package:flutter_lints/flutter.yaml analyzer: + exclude: + - test/*.mocks.dart language: strict-casts: true strict-inference: true diff --git a/flutter/ffi-cocoa.yaml b/flutter/ffi-cocoa.yaml index 5fdf4330c5..13e619fc8c 100644 --- a/flutter/ffi-cocoa.yaml +++ b/flutter/ffi-cocoa.yaml @@ -1,7 +1,7 @@ name: SentryCocoa description: Sentry Cocoa SDK FFI binding. language: objc -output: lib/src/sentry_cocoa.dart +output: lib/src/native/cocoa/binding.dart headers: entry-points: - ./cocoa_bindings_temp/Sentry.framework/Versions/A/PrivateHeaders/PrivateSentrySDKOnly.h diff --git a/flutter/lib/src/event_processor/native_app_start_event_processor.dart b/flutter/lib/src/event_processor/native_app_start_event_processor.dart index 2187204299..a7abe62e05 100644 --- a/flutter/lib/src/event_processor/native_app_start_event_processor.dart +++ b/flutter/lib/src/event_processor/native_app_start_event_processor.dart @@ -2,8 +2,7 @@ import 'dart:async'; import 'package:sentry/sentry.dart'; -import '../sentry_native.dart'; -import '../sentry_native_channel.dart'; +import '../native/sentry_native.dart'; /// EventProcessor that enriches [SentryTransaction] objects with app start /// measurement. diff --git a/flutter/lib/src/integrations/native_app_start_integration.dart b/flutter/lib/src/integrations/native_app_start_integration.dart index a47eb74717..47bf79dff4 100644 --- a/flutter/lib/src/integrations/native_app_start_integration.dart +++ b/flutter/lib/src/integrations/native_app_start_integration.dart @@ -2,7 +2,7 @@ import 'package:flutter/scheduler.dart'; import 'package:sentry/sentry.dart'; import '../sentry_flutter_options.dart'; -import '../sentry_native.dart'; +import '../native/sentry_native.dart'; import '../event_processor/native_app_start_event_processor.dart'; /// Integration which handles communication with native frameworks in order to diff --git a/flutter/lib/src/sentry_cocoa.dart b/flutter/lib/src/native/cocoa/binding.dart similarity index 100% rename from flutter/lib/src/sentry_cocoa.dart rename to flutter/lib/src/native/cocoa/binding.dart diff --git a/flutter/lib/src/method_channel_helper.dart b/flutter/lib/src/native/method_channel_helper.dart similarity index 100% rename from flutter/lib/src/method_channel_helper.dart rename to flutter/lib/src/native/method_channel_helper.dart diff --git a/flutter/lib/src/native_scope_observer.dart b/flutter/lib/src/native/native_scope_observer.dart similarity index 100% rename from flutter/lib/src/native_scope_observer.dart rename to flutter/lib/src/native/native_scope_observer.dart diff --git a/flutter/lib/src/sentry_native.dart b/flutter/lib/src/native/sentry_native.dart similarity index 79% rename from flutter/lib/src/sentry_native.dart rename to flutter/lib/src/native/sentry_native.dart index 3727294f74..6250831299 100644 --- a/flutter/lib/src/sentry_native.dart +++ b/flutter/lib/src/native/sentry_native.dart @@ -2,7 +2,7 @@ import 'dart:async'; import 'package:meta/meta.dart'; -import '../sentry_flutter.dart'; +import '../../sentry_flutter.dart'; import 'sentry_native_channel.dart'; /// [SentryNative] holds state that it fetches from to the native SDKs. Always @@ -98,3 +98,33 @@ class SentryNative { _didFetchAppStart = false; } } + +class NativeAppStart { + NativeAppStart(this.appStartTime, this.isColdStart); + + double appStartTime; + bool isColdStart; + + factory NativeAppStart.fromJson(Map json) { + return NativeAppStart( + json['appStartTime'] as double, + json['isColdStart'] as bool, + ); + } +} + +class NativeFrames { + NativeFrames(this.totalFrames, this.slowFrames, this.frozenFrames); + + int totalFrames; + int slowFrames; + int frozenFrames; + + factory NativeFrames.fromJson(Map json) { + return NativeFrames( + json['totalFrames'] as int, + json['slowFrames'] as int, + json['frozenFrames'] as int, + ); + } +} diff --git a/flutter/lib/src/sentry_native_channel.dart b/flutter/lib/src/native/sentry_native_channel.dart similarity index 84% rename from flutter/lib/src/sentry_native_channel.dart rename to flutter/lib/src/native/sentry_native_channel.dart index 44e4135b9f..63fd53bd06 100644 --- a/flutter/lib/src/sentry_native_channel.dart +++ b/flutter/lib/src/native/sentry_native_channel.dart @@ -3,10 +3,11 @@ import 'dart:async'; import 'package:flutter/services.dart'; import 'package:meta/meta.dart'; -import '../sentry_flutter.dart'; +import '../../sentry_flutter.dart'; +import 'sentry_native.dart'; import 'method_channel_helper.dart'; -/// Provide typed methods to access native layer. +/// Provide typed methods to access native layer via MethodChannel. @internal class SentryNativeChannel { SentryNativeChannel(this._channel, this._options); @@ -149,33 +150,3 @@ class SentryNativeChannel { ); } } - -class NativeAppStart { - NativeAppStart(this.appStartTime, this.isColdStart); - - double appStartTime; - bool isColdStart; - - factory NativeAppStart.fromJson(Map json) { - return NativeAppStart( - json['appStartTime'] as double, - json['isColdStart'] as bool, - ); - } -} - -class NativeFrames { - NativeFrames(this.totalFrames, this.slowFrames, this.frozenFrames); - - int totalFrames; - int slowFrames; - int frozenFrames; - - factory NativeFrames.fromJson(Map json) { - return NativeFrames( - json['totalFrames'] as int, - json['slowFrames'] as int, - json['frozenFrames'] as int, - ); - } -} diff --git a/flutter/lib/src/navigation/sentry_navigator_observer.dart b/flutter/lib/src/navigation/sentry_navigator_observer.dart index 135d131ec2..8b88b88088 100644 --- a/flutter/lib/src/navigation/sentry_navigator_observer.dart +++ b/flutter/lib/src/navigation/sentry_navigator_observer.dart @@ -1,8 +1,7 @@ import 'package:flutter/widgets.dart'; import '../../sentry_flutter.dart'; -import '../sentry_native.dart'; -import '../sentry_native_channel.dart'; +import '../native/sentry_native.dart'; /// This key must be used so that the web interface displays the events nicely /// See https://develop.sentry.dev/sdk/event-payloads/breadcrumbs/ diff --git a/flutter/lib/src/sentry_flutter.dart b/flutter/lib/src/sentry_flutter.dart index 13aa7cc552..688f10aac0 100644 --- a/flutter/lib/src/sentry_flutter.dart +++ b/flutter/lib/src/sentry_flutter.dart @@ -10,10 +10,10 @@ import 'event_processor/android_platform_exception_event_processor.dart'; import 'event_processor/flutter_exception_event_processor.dart'; import 'event_processor/platform_exception_event_processor.dart'; import 'integrations/screenshot_integration.dart'; -import 'native_scope_observer.dart'; +import 'native/native_scope_observer.dart'; import 'renderer/renderer.dart'; -import 'sentry_native.dart'; -import 'sentry_native_channel.dart'; +import 'native/sentry_native.dart'; +import 'native/sentry_native_channel.dart'; import 'integrations/integrations.dart'; import 'event_processor/flutter_enricher_event_processor.dart'; @@ -47,10 +47,10 @@ mixin SentryFlutter { flutterOptions.rendererWrapper = rendererWrapper; } - final nativeChannel = SentryNativeChannel(channel, flutterOptions); if (flutterOptions.platformChecker.hasNativeIntegration) { - final native = SentryNative(); - native.nativeChannel = nativeChannel; + // Set a default native channel to the singleton SentryNative instance. + SentryNative().nativeChannel = + SentryNativeChannel(channel, flutterOptions); } final platformDispatcher = PlatformDispatcher.instance; diff --git a/flutter/test/integrations/native_app_start_integration_test.dart b/flutter/test/integrations/native_app_start_integration_test.dart index b2ef832705..b4e06183c1 100644 --- a/flutter/test/integrations/native_app_start_integration_test.dart +++ b/flutter/test/integrations/native_app_start_integration_test.dart @@ -4,8 +4,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:sentry_flutter/src/integrations/native_app_start_integration.dart'; -import 'package:sentry_flutter/src/sentry_native.dart'; -import 'package:sentry_flutter/src/sentry_native_channel.dart'; +import 'package:sentry_flutter/src/native/sentry_native.dart'; import 'package:sentry/src/sentry_tracer.dart'; import '../mocks.dart'; diff --git a/flutter/test/method_channel_helper_test.dart b/flutter/test/method_channel_helper_test.dart index 018fc7ec67..12729e7313 100644 --- a/flutter/test/method_channel_helper_test.dart +++ b/flutter/test/method_channel_helper_test.dart @@ -1,5 +1,5 @@ import 'package:flutter_test/flutter_test.dart'; -import 'package:sentry_flutter/src/method_channel_helper.dart'; +import 'package:sentry_flutter/src/native/method_channel_helper.dart'; import 'package:collection/collection.dart'; void main() { diff --git a/flutter/test/mocks.dart b/flutter/test/mocks.dart index 28da5e6bff..39209f7015 100644 --- a/flutter/test/mocks.dart +++ b/flutter/test/mocks.dart @@ -11,8 +11,8 @@ import 'package:sentry/src/sentry_tracer.dart'; import 'package:meta/meta.dart'; import 'package:sentry_flutter/src/binding_wrapper.dart'; import 'package:sentry_flutter/src/renderer/renderer.dart'; -import 'package:sentry_flutter/src/sentry_native.dart'; -import 'package:sentry_flutter/src/sentry_native_channel.dart'; +import 'package:sentry_flutter/src/native/sentry_native.dart'; +import 'package:sentry_flutter/src/native/sentry_native_channel.dart'; import 'mocks.mocks.dart'; import 'no_such_method_provider.dart'; diff --git a/flutter/test/mocks.mocks.dart b/flutter/test/mocks.mocks.dart index 70a42aff77..b92e8cfba8 100644 --- a/flutter/test/mocks.mocks.dart +++ b/flutter/test/mocks.mocks.dart @@ -13,8 +13,8 @@ import 'package:sentry/sentry.dart' as _i2; import 'package:sentry/src/protocol.dart' as _i3; import 'package:sentry/src/sentry_envelope.dart' as _i7; import 'package:sentry/src/sentry_tracer.dart' as _i8; -import 'package:sentry_flutter/src/sentry_native.dart' as _i10; -import 'package:sentry_flutter/src/sentry_native_channel.dart' as _i11; +import 'package:sentry_flutter/src/native/sentry_native.dart' as _i10; +import 'package:sentry_flutter/src/native/sentry_native_channel.dart' as _i11; import 'mocks.dart' as _i12; @@ -112,8 +112,18 @@ class _FakeSentryId_7 extends _i1.SmartFake implements _i3.SentryId { ); } -class _FakeHub_8 extends _i1.SmartFake implements _i2.Hub { - _FakeHub_8( +class _FakeScope_8 extends _i1.SmartFake implements _i2.Scope { + _FakeScope_8( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeHub_9 extends _i1.SmartFake implements _i2.Hub { + _FakeHub_9( Object parent, Invocation parentInvocation, ) : super( @@ -144,7 +154,6 @@ class MockTransport extends _i1.Mock implements _i2.Transport { /// A class which mocks [SentryTracer]. /// /// See the documentation for Mockito's code generation for more information. -// ignore: invalid_use_of_internal_member class MockSentryTracer extends _i1.Mock implements _i8.SentryTracer { MockSentryTracer() { _i1.throwOnMissingStub(this); @@ -526,13 +535,13 @@ class MockSentryNative extends _i1.Mock implements _i10.SentryNative { returnValue: false, ) as bool); @override - _i6.Future<_i11.NativeAppStart?> fetchNativeAppStart() => (super.noSuchMethod( + _i6.Future<_i10.NativeAppStart?> fetchNativeAppStart() => (super.noSuchMethod( Invocation.method( #fetchNativeAppStart, [], ), - returnValue: _i6.Future<_i11.NativeAppStart?>.value(), - ) as _i6.Future<_i11.NativeAppStart?>); + returnValue: _i6.Future<_i10.NativeAppStart?>.value(), + ) as _i6.Future<_i10.NativeAppStart?>); @override _i6.Future beginNativeFramesCollection() => (super.noSuchMethod( Invocation.method( @@ -543,15 +552,15 @@ class MockSentryNative extends _i1.Mock implements _i10.SentryNative { returnValueForMissingStub: _i6.Future.value(), ) as _i6.Future); @override - _i6.Future<_i11.NativeFrames?> endNativeFramesCollection( + _i6.Future<_i10.NativeFrames?> endNativeFramesCollection( _i3.SentryId? traceId) => (super.noSuchMethod( Invocation.method( #endNativeFramesCollection, [traceId], ), - returnValue: _i6.Future<_i11.NativeFrames?>.value(), - ) as _i6.Future<_i11.NativeFrames?>); + returnValue: _i6.Future<_i10.NativeFrames?>.value(), + ) as _i6.Future<_i10.NativeFrames?>); @override _i6.Future setContexts( String? key, @@ -695,6 +704,14 @@ class MockHub extends _i1.Mock implements _i2.Hub { ), ) as _i3.SentryId); @override + _i2.Scope get scope => (super.noSuchMethod( + Invocation.getter(#scope), + returnValue: _FakeScope_8( + this, + Invocation.getter(#scope), + ), + ) as _i2.Scope); + @override _i6.Future<_i3.SentryId> captureEvent( _i3.SentryEvent? event, { dynamic stackTrace, @@ -828,7 +845,7 @@ class MockHub extends _i1.Mock implements _i2.Hub { #clone, [], ), - returnValue: _FakeHub_8( + returnValue: _FakeHub_9( this, Invocation.method( #clone, diff --git a/flutter/test/native_scope_observer_test.dart b/flutter/test/native_scope_observer_test.dart index 0efb22a2c1..916bd4b7be 100644 --- a/flutter/test/native_scope_observer_test.dart +++ b/flutter/test/native_scope_observer_test.dart @@ -2,7 +2,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:sentry/sentry.dart'; -import 'package:sentry_flutter/src/native_scope_observer.dart'; +import 'package:sentry_flutter/src/native/native_scope_observer.dart'; import 'mocks.dart'; diff --git a/flutter/test/sentry_flutter_test.dart b/flutter/test/sentry_flutter_test.dart index 56f6f250a6..4621ae3b7f 100644 --- a/flutter/test/sentry_flutter_test.dart +++ b/flutter/test/sentry_flutter_test.dart @@ -6,7 +6,7 @@ import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:sentry_flutter/src/integrations/integrations.dart'; import 'package:sentry_flutter/src/integrations/screenshot_integration.dart'; import 'package:sentry_flutter/src/renderer/renderer.dart'; -import 'package:sentry_flutter/src/sentry_native.dart'; +import 'package:sentry_flutter/src/native/sentry_native.dart'; import 'package:sentry_flutter/src/version.dart'; import 'package:sentry_flutter/src/view_hierarchy/view_hierarchy_integration.dart'; import 'mocks.dart'; diff --git a/flutter/test/sentry_flutter_util.dart b/flutter/test/sentry_flutter_util.dart index dcff13c054..7397c4a6a5 100644 --- a/flutter/test/sentry_flutter_util.dart +++ b/flutter/test/sentry_flutter_util.dart @@ -1,7 +1,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:sentry_flutter/src/file_system_transport.dart'; -import 'package:sentry_flutter/src/native_scope_observer.dart'; +import 'package:sentry_flutter/src/native/native_scope_observer.dart'; void testTransport({ required Transport transport, diff --git a/flutter/test/sentry_native_channel_test.dart b/flutter/test/sentry_native_channel_test.dart index 2264f2fad0..cd05bf71ea 100644 --- a/flutter/test/sentry_native_channel_test.dart +++ b/flutter/test/sentry_native_channel_test.dart @@ -5,9 +5,9 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; -import 'package:sentry_flutter/src/method_channel_helper.dart'; -import 'package:sentry_flutter/src/sentry_native.dart'; -import 'package:sentry_flutter/src/sentry_native_channel.dart'; +import 'package:sentry_flutter/src/native/method_channel_helper.dart'; +import 'package:sentry_flutter/src/native/sentry_native.dart'; +import 'package:sentry_flutter/src/native/sentry_native_channel.dart'; import 'mocks.mocks.dart'; void main() { diff --git a/flutter/test/sentry_native_test.dart b/flutter/test/sentry_native_test.dart index 4d38a45122..d6b5fab583 100644 --- a/flutter/test/sentry_native_test.dart +++ b/flutter/test/sentry_native_test.dart @@ -2,8 +2,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; -import 'package:sentry_flutter/src/sentry_native.dart'; -import 'package:sentry_flutter/src/sentry_native_channel.dart'; +import 'package:sentry_flutter/src/native/sentry_native.dart'; import 'mocks.dart'; void main() { diff --git a/flutter/test/sentry_navigator_observer_test.dart b/flutter/test/sentry_navigator_observer_test.dart index d4c2499efc..c9a1629362 100644 --- a/flutter/test/sentry_navigator_observer_test.dart +++ b/flutter/test/sentry_navigator_observer_test.dart @@ -5,8 +5,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; -import 'package:sentry_flutter/src/sentry_native.dart'; -import 'package:sentry_flutter/src/sentry_native_channel.dart'; +import 'package:sentry_flutter/src/native/sentry_native.dart'; import 'package:sentry/src/sentry_tracer.dart'; import 'mocks.dart';