diff --git a/dart/lib/src/hub.dart b/dart/lib/src/hub.dart index 175b96ec6a..4b081f5371 100644 --- a/dart/lib/src/hub.dart +++ b/dart/lib/src/hub.dart @@ -273,6 +273,9 @@ class Hub { exception: exception, stackTrace: stackTrace, ); + if (_options.devMode) { + rethrow; + } } } return scope; @@ -367,6 +370,9 @@ class Hub { SentryLevel.error, "Error in the 'configureScope' callback, error: $err", ); + if (_options.devMode) { + rethrow; + } } } } diff --git a/dart/lib/src/scope.dart b/dart/lib/src/scope.dart index 1aec375e15..3acb71b66a 100644 --- a/dart/lib/src/scope.dart +++ b/dart/lib/src/scope.dart @@ -171,6 +171,9 @@ class Scope { exception: exception, stackTrace: stackTrace, ); + if (_options.devMode) { + rethrow; + } } } if (processedBreadcrumb != null) { @@ -329,6 +332,9 @@ class Scope { exception: exception, stackTrace: stackTrace, ); + if (_options.devMode) { + rethrow; + } } if (processedEvent == null) { _options.logger(SentryLevel.debug, 'Event was dropped by a processor'); diff --git a/dart/lib/src/sentry.dart b/dart/lib/src/sentry.dart index bbc3ec0ad0..b3ec82ce10 100644 --- a/dart/lib/src/sentry.dart +++ b/dart/lib/src/sentry.dart @@ -43,6 +43,7 @@ class Sentry { @internal SentryOptions? options, }) async { final sentryOptions = options ?? SentryOptions(); + await _initDefaultValues(sentryOptions); try { @@ -57,6 +58,9 @@ class Sentry { exception: exception, stackTrace: stackTrace, ); + if (sentryOptions.devMode) { + rethrow; + } } if (sentryOptions.dsn == null) { diff --git a/dart/lib/src/sentry_client.dart b/dart/lib/src/sentry_client.dart index 4d543d890c..44489f42a6 100644 --- a/dart/lib/src/sentry_client.dart +++ b/dart/lib/src/sentry_client.dart @@ -395,6 +395,9 @@ class SentryClient { exception: exception, stackTrace: stackTrace, ); + if (_options.devMode) { + rethrow; + } } if (eventOrTransaction == null) { @@ -429,6 +432,9 @@ class SentryClient { exception: exception, stackTrace: stackTrace, ); + if (_options.devMode) { + rethrow; + } } if (processedEvent == null) { _recordLostEvent(event, DiscardReason.eventProcessor); diff --git a/dart/lib/src/sentry_options.dart b/dart/lib/src/sentry_options.dart index 93a7f80bdc..e396a28670 100644 --- a/dart/lib/src/sentry_options.dart +++ b/dart/lib/src/sentry_options.dart @@ -343,6 +343,11 @@ class SentryOptions { _extractorsByType[extractor.exceptionType] = extractor; } + /// Changed SDK behaviour when set to true: + /// - Rethrow exceptions that occur in user provided closures + @internal + bool devMode = false; + SentryOptions({this.dsn, PlatformChecker? checker}) { if (checker != null) { platformChecker = checker; diff --git a/dart/lib/src/sentry_traces_sampler.dart b/dart/lib/src/sentry_traces_sampler.dart index ce722fde60..1391047d97 100644 --- a/dart/lib/src/sentry_traces_sampler.dart +++ b/dart/lib/src/sentry_traces_sampler.dart @@ -38,6 +38,9 @@ class SentryTracesSampler { exception: exception, stackTrace: stackTrace, ); + if (_options.devMode) { + rethrow; + } } } diff --git a/dart/test/environment_test.dart b/dart/test/environment_test.dart index c191e58ae4..6a409022c5 100644 --- a/dart/test/environment_test.dart +++ b/dart/test/environment_test.dart @@ -23,6 +23,7 @@ void main() { release: 'release-9.8.7', dist: 'bar', ); + options.devMode = true; await Sentry.init( (options) => options, @@ -43,6 +44,7 @@ void main() { release: 'release-9.8.7', dist: 'bar', ); + options.devMode = true; await Sentry.init( (options) => options, diff --git a/dart/test/event_processor/deduplication_event_processor_test.dart b/dart/test/event_processor/deduplication_event_processor_test.dart index 534cb1103b..47540cf035 100644 --- a/dart/test/event_processor/deduplication_event_processor_test.dart +++ b/dart/test/event_processor/deduplication_event_processor_test.dart @@ -77,12 +77,14 @@ void main() { final transport = MockTransport(); + final options = SentryOptions(dsn: fakeDsn)..devMode = true; await Sentry.init( (options) { options.dsn = fakeDsn; options.transport = transport; options.enableDeduplication = true; }, + options: options, ); // The test doesn't work if `outerTestMethod` is passed as diff --git a/dart/test/event_processor/enricher/io_enricher_test.dart b/dart/test/event_processor/enricher/io_enricher_test.dart index 56e9148f23..3c1108a863 100644 --- a/dart/test/event_processor/enricher/io_enricher_test.dart +++ b/dart/test/event_processor/enricher/io_enricher_test.dart @@ -159,16 +159,18 @@ void main() { }); test('$IoEnricherEventProcessor gets added on init', () async { - late SentryOptions sentryOptions; + final options = SentryOptions(dsn: fakeDsn)..devMode = true; + late SentryOptions configuredOptions; await Sentry.init( (options) { options.dsn = fakeDsn; - sentryOptions = options; + configuredOptions = options; }, + options: options, ); await Sentry.close(); - final ioEnricherCount = sentryOptions.eventProcessors + final ioEnricherCount = configuredOptions.eventProcessors .whereType() .length; expect(ioEnricherCount, 1); diff --git a/dart/test/initialization_test.dart b/dart/test/initialization_test.dart index 785f45faf8..fae9f26e82 100644 --- a/dart/test/initialization_test.dart +++ b/dart/test/initialization_test.dart @@ -14,28 +14,42 @@ void main() { }); test('async re-initilization', () async { - await Sentry.init((options) { - options.dsn = fakeDsn; - }); + final options = SentryOptions(dsn: fakeDsn)..devMode = true; + await Sentry.init( + (options) { + options.dsn = fakeDsn; + }, + options: options, + ); await Sentry.close(); - await Sentry.init((options) { - options.dsn = fakeDsn; - }); + await Sentry.init( + (options) { + options.dsn = fakeDsn; + }, + options: options, + ); }); // This is the failure from // https://github.com/getsentry/sentry-dart/issues/508 test('re-initilization', () async { - await Sentry.init((options) { - options.dsn = fakeDsn; - }); + final options = SentryOptions(dsn: fakeDsn)..devMode = true; + await Sentry.init( + (options) { + options.dsn = fakeDsn; + }, + options: options, + ); await Sentry.close(); - await Sentry.init((options) { - options.dsn = fakeDsn; - }); + await Sentry.init( + (options) { + options.dsn = fakeDsn; + }, + options: options, + ); }); } diff --git a/dart/test/sentry_test.dart b/dart/test/sentry_test.dart index df28266f25..2705f23161 100644 --- a/dart/test/sentry_test.dart +++ b/dart/test/sentry_test.dart @@ -18,7 +18,9 @@ void main() { var anException = Exception(); setUp(() async { + final options = SentryOptions(dsn: fakeDsn)..devMode = true; await Sentry.init( + options: options, (options) => { options.dsn = fakeDsn, options.tracesSampleRate = 1.0, @@ -135,8 +137,12 @@ void main() { }); test('null DSN', () async { + final options = SentryOptions(dsn: fakeDsn)..devMode = true; expect( - () async => await Sentry.init((options) => options.dsn = null), + () async => await Sentry.init( + options: options, + (options) => options.dsn = null, + ), throwsArgumentError, ); expect(Sentry.isEnabled, false); @@ -144,19 +150,29 @@ void main() { test('appRunner should be optional', () async { expect(Sentry.isEnabled, false); - await Sentry.init((options) => options.dsn = fakeDsn); + final options = SentryOptions(dsn: fakeDsn)..devMode = true; + await Sentry.init( + options: options, + (options) => options.dsn = fakeDsn, + ); expect(Sentry.isEnabled, true); }); test('empty DSN', () async { - await Sentry.init((options) => options.dsn = ''); + final options = SentryOptions(dsn: fakeDsn)..devMode = true; + await Sentry.init( + options: options, + (options) => options.dsn = '', + ); expect(Sentry.isEnabled, false); }); test('empty DSN disables the SDK but runs the integrations', () async { final integration = MockIntegration(); + final options = SentryOptions(dsn: fakeDsn)..devMode = true; await Sentry.init( + options: options, (options) { options.dsn = ''; options.addIntegration(integration); @@ -167,7 +183,11 @@ void main() { }); test('close disables the SDK', () async { - await Sentry.init((options) => options.dsn = fakeDsn); + final options = SentryOptions(dsn: fakeDsn)..devMode = true; + await Sentry.init( + options: options, + (options) => options.dsn = fakeDsn, + ); Sentry.bindClient(MockSentryClient()); @@ -187,7 +207,9 @@ void main() { test('should install integrations', () async { final integration = MockIntegration(); + final options = SentryOptions(dsn: fakeDsn)..devMode = true; await Sentry.init( + options: options, (options) { options.dsn = fakeDsn; options.addIntegration(integration); @@ -199,7 +221,9 @@ void main() { test('should add default integrations', () async { late SentryOptions optionsReference; + final options = SentryOptions(dsn: fakeDsn)..devMode = true; await Sentry.init( + options: options, (options) { options.dsn = fakeDsn; optionsReference = options; @@ -221,7 +245,9 @@ void main() { }, onPlatform: {'browser': Skip()}); test('should add only web compatible default integrations', () async { + final options = SentryOptions(dsn: fakeDsn)..devMode = true; await Sentry.init( + options: options, (options) { options.dsn = fakeDsn; expect( @@ -235,7 +261,9 @@ void main() { test('should close integrations', () async { final integration = MockIntegration(); + final options = SentryOptions(dsn: fakeDsn)..devMode = true; await Sentry.init( + options: options, (options) { options.dsn = fakeDsn; options.addIntegration(integration); @@ -249,7 +277,9 @@ void main() { }); test('$DeduplicationEventProcessor is added on init', () async { + final options = SentryOptions(dsn: fakeDsn)..devMode = true; await Sentry.init( + options: options, (options) { options.dsn = fakeDsn; final count = options.eventProcessors @@ -264,7 +294,9 @@ void main() { final completer = Completer(); var completed = false; + final options = SentryOptions(dsn: fakeDsn)..devMode = true; final init = Sentry.init( + options: options, (options) { options.dsn = fakeDsn; }, @@ -289,7 +321,9 @@ void main() { final completer = Completer(); var completed = false; + final options = SentryOptions(dsn: fakeDsn)..devMode = true; final init = Sentry.init( + options: options, (options) { options.dsn = fakeDsn; }, @@ -311,51 +345,68 @@ void main() { test('options.environment debug', () async { final sentryOptions = SentryOptions(dsn: fakeDsn) + ..devMode = true ..platformChecker = FakePlatformChecker.debugMode(); - await Sentry.init((options) { - options.dsn = fakeDsn; - expect(options.environment, 'debug'); - expect(options.debug, false); - }, options: sentryOptions); + final options = SentryOptions(); + options.devMode = true; + await Sentry.init( + (options) { + options.dsn = fakeDsn; + expect(options.environment, 'debug'); + expect(options.debug, false); + }, + options: sentryOptions, + ); }); test('options.environment profile', () async { final sentryOptions = - SentryOptions(dsn: fakeDsn, checker: FakePlatformChecker.profileMode()); + SentryOptions(dsn: fakeDsn, checker: FakePlatformChecker.profileMode()) + ..devMode = true; - await Sentry.init((options) { - options.dsn = fakeDsn; - expect(options.environment, 'profile'); - expect(options.debug, false); - }, options: sentryOptions); + await Sentry.init( + (options) { + options.dsn = fakeDsn; + expect(options.environment, 'profile'); + expect(options.debug, false); + }, + options: sentryOptions, + ); }); test('options.environment production (defaultEnvironment)', () async { final sentryOptions = - SentryOptions(dsn: fakeDsn, checker: FakePlatformChecker.releaseMode()); - - await Sentry.init((options) { - options.dsn = fakeDsn; - expect(options.environment, 'production'); - expect(options.debug, false); - }, options: sentryOptions); + SentryOptions(dsn: fakeDsn, checker: FakePlatformChecker.releaseMode()) + ..devMode = true; + await Sentry.init( + (options) { + options.dsn = fakeDsn; + expect(options.environment, 'production'); + expect(options.debug, false); + }, + options: sentryOptions, + ); }); test('options.logger is set by setting the debug flag', () async { final sentryOptions = - SentryOptions(dsn: fakeDsn, checker: FakePlatformChecker.debugMode()); + SentryOptions(dsn: fakeDsn, checker: FakePlatformChecker.debugMode()) + ..devMode = true; - await Sentry.init((options) { - options.dsn = fakeDsn; - options.debug = true; - // ignore: deprecated_member_use_from_same_package - expect(options.logger, isNot(noOpLogger)); + await Sentry.init( + (options) { + options.dsn = fakeDsn; + options.debug = true; + // ignore: deprecated_member_use_from_same_package + expect(options.logger, isNot(noOpLogger)); - options.debug = false; - // ignore: deprecated_member_use_from_same_package - expect(options.logger, noOpLogger); - }, options: sentryOptions); + options.debug = false; + // ignore: deprecated_member_use_from_same_package + expect(options.logger, noOpLogger); + }, + options: sentryOptions, + ); // ignore: deprecated_member_use_from_same_package expect(sentryOptions.logger, isNot(dartLogger)); @@ -366,13 +417,17 @@ void main() { test('throw is handled and logged', () async { final sentryOptions = SentryOptions(dsn: fakeDsn) + ..devMode = false ..debug = true ..logger = fixture.mockLogger; final exception = Exception("Exception in options callback"); - await Sentry.init((options) async { - throw exception; - }, options: sentryOptions); + await Sentry.init( + (options) async { + throw exception; + }, + options: sentryOptions, + ); expect(fixture.loggedException, exception); expect(fixture.loggedLevel, SentryLevel.error); @@ -384,13 +439,17 @@ void main() { test('throw is handled and logged', () async { final sentryOptions = SentryOptions(dsn: fakeDsn) + ..devMode = false ..debug = true ..logger = fixture.mockLogger; final exception = Exception("Exception in options callback"); - await Sentry.init((options) async { - throw exception; - }, options: sentryOptions); + await Sentry.init( + (options) async { + throw exception; + }, + options: sentryOptions, + ); expect(fixture.loggedException, exception); expect(fixture.loggedLevel, SentryLevel.error); diff --git a/e2e_test/bin/e2e_test.dart b/e2e_test/bin/e2e_test.dart index 7c1ec036d1..785f98ea72 100644 --- a/e2e_test/bin/e2e_test.dart +++ b/e2e_test/bin/e2e_test.dart @@ -18,9 +18,16 @@ void main(List arguments) async { print('AUTH TOKEN is not set'); exit(1); } - await Sentry.init((options) { - options.dsn = _exampleDsn; - }); + final options = SentryOptions(dsn: _exampleDsn) + // ignore: invalid_use_of_internal_member + ..devMode = true; + await Sentry.init( + (options) { + options.dsn = _exampleDsn; + }, + // ignore: invalid_use_of_internal_member + options: options, + ); var id = SentryId.empty(); try { diff --git a/flutter/test/initialization_test.dart b/flutter/test/initialization_test.dart index e8a8c682d0..cf1374df37 100644 --- a/flutter/test/initialization_test.dart +++ b/flutter/test/initialization_test.dart @@ -14,15 +14,23 @@ void main() { }); test('async re-initilization', () async { - await SentryFlutter.init((options) { - options.dsn = fakeDsn; - }); + await SentryFlutter.init( + (options) { + options.dsn = fakeDsn; + // ignore: invalid_use_of_internal_member + options.devMode = true; + }, + ); await Sentry.close(); - await SentryFlutter.init((options) { - options.dsn = fakeDsn; - }); + await SentryFlutter.init( + (options) { + options.dsn = fakeDsn; + // ignore: invalid_use_of_internal_member + options.devMode = true; + }, + ); await Sentry.close(); }); @@ -30,15 +38,23 @@ void main() { // This is the failure from // https://github.com/getsentry/sentry-dart/issues/508 test('re-initilization', () async { - await SentryFlutter.init((options) { - options.dsn = fakeDsn; - }); + await SentryFlutter.init( + (options) { + options.dsn = fakeDsn; + // ignore: invalid_use_of_internal_member + options.devMode = true; + }, + ); await Sentry.close(); - await SentryFlutter.init((options) { - options.dsn = fakeDsn; - }); + await SentryFlutter.init( + (options) { + options.dsn = fakeDsn; + // ignore: invalid_use_of_internal_member + options.devMode = true; + }, + ); await Sentry.close(); }); diff --git a/flutter/test/sentry_flutter_test.dart b/flutter/test/sentry_flutter_test.dart index c67ebf4acf..b5770d6dda 100644 --- a/flutter/test/sentry_flutter_test.dart +++ b/flutter/test/sentry_flutter_test.dart @@ -64,6 +64,7 @@ void main() { await SentryFlutter.init( (options) async { options.dsn = fakeDsn; + options.devMode = true; integrations = options.integrations; transport = options.transport; sentryFlutterOptions = options; @@ -111,6 +112,7 @@ void main() { await SentryFlutter.init( (options) async { options.dsn = fakeDsn; + options.devMode = true; integrations = options.integrations; transport = options.transport; sentryFlutterOptions = options; @@ -156,6 +158,7 @@ void main() { await SentryFlutter.init( (options) async { options.dsn = fakeDsn; + options.devMode = true; integrations = options.integrations; transport = options.transport; sentryFlutterOptions = options; @@ -201,6 +204,7 @@ void main() { await SentryFlutter.init( (options) async { options.dsn = fakeDsn; + options.devMode = true; integrations = options.integrations; transport = options.transport; sentryFlutterOptions = options; @@ -249,6 +253,7 @@ void main() { await SentryFlutter.init( (options) async { options.dsn = fakeDsn; + options.devMode = true; integrations = options.integrations; transport = options.transport; sentryFlutterOptions = options; @@ -297,6 +302,7 @@ void main() { await SentryFlutter.init( (options) async { options.dsn = fakeDsn; + options.devMode = true; integrations = options.integrations; transport = options.transport; sentryFlutterOptions = options; @@ -347,6 +353,7 @@ void main() { await SentryFlutter.init( (options) async { options.dsn = fakeDsn; + options.devMode = true; integrations = options.integrations; transport = options.transport; }, @@ -390,6 +397,7 @@ void main() { await SentryFlutter.init( (options) async { options.dsn = fakeDsn; + options.devMode = true; integrations = options.integrations; transport = options.transport; }, @@ -432,6 +440,7 @@ void main() { await SentryFlutter.init( (options) async { options.dsn = fakeDsn; + options.devMode = true; integrations = options.integrations; transport = options.transport; }, @@ -475,13 +484,16 @@ void main() { test('installed with skia renderer', () async { List integrations = []; - await SentryFlutter.init((options) async { - options.dsn = fakeDsn; - integrations = options.integrations; - }, - appRunner: appRunner, - platformChecker: getPlatformChecker(platform: MockPlatform.iOs()), - rendererWrapper: MockRendererWrapper(FlutterRenderer.skia)); + await SentryFlutter.init( + (options) async { + options.dsn = fakeDsn; + options.devMode = true; + integrations = options.integrations; + }, + appRunner: appRunner, + platformChecker: getPlatformChecker(platform: MockPlatform.iOs()), + rendererWrapper: MockRendererWrapper(FlutterRenderer.skia), + ); expect( integrations @@ -495,13 +507,16 @@ void main() { test('installed with canvasKit renderer', () async { List integrations = []; - await SentryFlutter.init((options) async { - options.dsn = fakeDsn; - integrations = options.integrations; - }, - appRunner: appRunner, - platformChecker: getPlatformChecker(platform: MockPlatform.iOs()), - rendererWrapper: MockRendererWrapper(FlutterRenderer.canvasKit)); + await SentryFlutter.init( + (options) async { + options.dsn = fakeDsn; + options.devMode = true; + integrations = options.integrations; + }, + appRunner: appRunner, + platformChecker: getPlatformChecker(platform: MockPlatform.iOs()), + rendererWrapper: MockRendererWrapper(FlutterRenderer.canvasKit), + ); expect( integrations @@ -515,13 +530,16 @@ void main() { test('not installed with html renderer', () async { List integrations = []; - await SentryFlutter.init((options) async { - options.dsn = fakeDsn; - integrations = options.integrations; - }, - appRunner: appRunner, - platformChecker: getPlatformChecker(platform: MockPlatform.iOs()), - rendererWrapper: MockRendererWrapper(FlutterRenderer.html)); + await SentryFlutter.init( + (options) async { + options.dsn = fakeDsn; + options.devMode = true; + integrations = options.integrations; + }, + appRunner: appRunner, + platformChecker: getPlatformChecker(platform: MockPlatform.iOs()), + rendererWrapper: MockRendererWrapper(FlutterRenderer.html), + ); expect( integrations @@ -535,13 +553,16 @@ void main() { test('not installed with unknown renderer', () async { List integrations = []; - await SentryFlutter.init((options) async { - options.dsn = fakeDsn; - integrations = options.integrations; - }, - appRunner: appRunner, - platformChecker: getPlatformChecker(platform: MockPlatform.iOs()), - rendererWrapper: MockRendererWrapper(FlutterRenderer.unknown)); + await SentryFlutter.init( + (options) async { + options.dsn = fakeDsn; + options.devMode = true; + integrations = options.integrations; + }, + appRunner: appRunner, + platformChecker: getPlatformChecker(platform: MockPlatform.iOs()), + rendererWrapper: MockRendererWrapper(FlutterRenderer.unknown), + ); expect( integrations @@ -563,6 +584,7 @@ void main() { await SentryFlutter.init( (options) { options.dsn = fakeDsn; + options.devMode = true; expect(false, options.debug); expect('debug', options.environment);