diff --git a/CHANGELOG.md b/CHANGELOG.md index aaa95738..4175ed10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 2.4.0 (2022-12-01) + +- Added `maxStringValueLength` option to `bugsnag.start` to allow truncation behaviour to be configured. + [#179](https://github.com/bugsnag/bugsnag-flutter/pull/179) +- Native-first hot-reloads (using `bugnag.attach`) will no longer cause errors, but will instead emit a warning + [#182](https://github.com/bugsnag/bugsnag-flutter/pull/182) +- Update bugsnag-android from v5.28.1 to [v5.28.3](https://github.com/bugsnag/bugsnag-android/blob/master/CHANGELOG.md#5283-2022-11-16) + ## 2.3.0 (2022-10-27) - Added `BugsnagTelemetryType.usage` to allow sending of usage telemetry to be disabled. diff --git a/features/attach_flutter.feature b/features/attach_flutter.feature index b8349761..8e47bc6b 100644 --- a/features/attach_flutter.feature +++ b/features/attach_flutter.feature @@ -39,3 +39,39 @@ Feature: Attach to running native Bugsnag instance When I configure the app to run in the "disableDartErrors" state And I run "AttachBugsnagScenario" Then I should receive no errors + + Scenario: multiple attaches with a handled exception + When I configure the app to run in the "handled extra-attach" state + And I run "AttachBugsnagScenario" + Then I wait to receive 2 errors + And the error is valid for the error reporting API version "4.0" for the "Flutter Bugsnag Notifier" notifier + And the exception "errorClass" equals "_Exception" + And the exception "message" equals "Handled exception with attached info" + And the error payload field "events.0.unhandled" is false + And the error payload field "events.0.threads" is a non-empty array + And the event "severity" equals "warning" + + And the event "user.id" equals "test-user-id" + And the event "user.email" is null + And the event "user.name" equals "Old Man Tables" + + And the event "context" equals "flutter-test-context" + And event 0 contains the feature flag "demo-mode" with no variant + And event 0 contains the feature flag "sample-group" with variant "123" + + Scenario: multiple attaches with an unhandled exception + When I configure the app to run in the "extra-attach" state + When I run "AttachBugsnagScenario" + Then I wait to receive 2 errors + And the error is valid for the error reporting API version "4.0" for the "Flutter Bugsnag Notifier" notifier + And the exception "errorClass" equals "_Exception" + And the exception "message" equals "Unhandled exception with attached info" + And the error payload field "events.0.threads" is a non-empty array + And the event "context" equals "flutter-test-context" + And the event "severity" equals "error" + And the event "unhandled" is true + And the event "user.email" is null + And the event "user.id" equals "test-user-id" + And the event "user.name" equals "Old Man Tables" + And event 0 contains the feature flag "demo-mode" with no variant + And event 0 contains the feature flag "sample-group" with variant "123" diff --git a/features/fixtures/app/lib/scenarios/attach_bugsnag_scenario.dart b/features/fixtures/app/lib/scenarios/attach_bugsnag_scenario.dart index 0ea3e8cd..4e095ddb 100644 --- a/features/fixtures/app/lib/scenarios/attach_bugsnag_scenario.dart +++ b/features/fixtures/app/lib/scenarios/attach_bugsnag_scenario.dart @@ -5,6 +5,14 @@ class AttachBugsnagScenario extends Scenario { @override Future run() async { await startNativeNotifier(); + + final attachFuture = await doAttach(); + if (extraConfig?.contains("extra-attach") == true) { + await doAttach(); + } + } + + Future doAttach() async { await bugsnag.attach( runApp: () async { await Future.wait([ diff --git a/packages/bugsnag_breadcrumbs_dart_io/pubspec.yaml b/packages/bugsnag_breadcrumbs_dart_io/pubspec.yaml index 85176ce8..37015645 100644 --- a/packages/bugsnag_breadcrumbs_dart_io/pubspec.yaml +++ b/packages/bugsnag_breadcrumbs_dart_io/pubspec.yaml @@ -1,6 +1,6 @@ name: bugsnag_breadcrumbs_dart_io description: Bugsnag network breadcrumbs for dart:io's HttpClient -version: 2.3.0 +version: 2.4.0 homepage: https://www.bugsnag.com/ documentation: https://docs.bugsnag.com/platforms/flutter/ repository: https://github.com/bugsnag/bugsnag-flutter diff --git a/packages/bugsnag_breadcrumbs_http/pubspec.yaml b/packages/bugsnag_breadcrumbs_http/pubspec.yaml index 724b453e..dc4dcf51 100644 --- a/packages/bugsnag_breadcrumbs_http/pubspec.yaml +++ b/packages/bugsnag_breadcrumbs_http/pubspec.yaml @@ -1,6 +1,6 @@ name: bugsnag_breadcrumbs_http description: Bugsnag network breadcrumbs for https://pub.dev/packages/http -version: 2.3.0 +version: 2.4.0 homepage: https://www.bugsnag.com/ documentation: https://docs.bugsnag.com/platforms/flutter/ repository: https://github.com/bugsnag/bugsnag-flutter diff --git a/packages/bugsnag_flutter/android/build.gradle b/packages/bugsnag_flutter/android/build.gradle index 6447dba5..6f2ee785 100644 --- a/packages/bugsnag_flutter/android/build.gradle +++ b/packages/bugsnag_flutter/android/build.gradle @@ -46,7 +46,7 @@ android { } dependencies { - implementation 'com.bugsnag:bugsnag-android:5.28.1' + implementation 'com.bugsnag:bugsnag-android:5.28.3' testImplementation 'junit:junit:4.12' } diff --git a/packages/bugsnag_flutter/android/src/main/java/com/bugsnag/flutter/BugsnagFlutter.java b/packages/bugsnag_flutter/android/src/main/java/com/bugsnag/flutter/BugsnagFlutter.java index 73ab1eb2..dabab274 100644 --- a/packages/bugsnag_flutter/android/src/main/java/com/bugsnag/flutter/BugsnagFlutter.java +++ b/packages/bugsnag_flutter/android/src/main/java/com/bugsnag/flutter/BugsnagFlutter.java @@ -37,8 +37,7 @@ class BugsnagFlutter { private InternalHooks client; - private static boolean isAnyAttached = false; - private boolean isAttached = false; + private static boolean isAttached = false; private static boolean isAnyStarted = false; private boolean isStarted = false; @@ -53,10 +52,6 @@ class BugsnagFlutter { Context context; JSONObject attach(@NonNull JSONObject args) throws Exception { - if (isAttached) { - throw new IllegalStateException("bugsnag.attach() may not be called more than once"); - } - JSONObject result = new JSONObject() .put("config", new JSONObject() .put("enabledErrorTypes", new JSONObject() @@ -64,8 +59,8 @@ JSONObject attach(@NonNull JSONObject args) throws Exception { ) ); - if (isAnyAttached) { - Log.i("BugsnagFlutter", "bugsnag.attach() was called from a previous Flutter context. Ignoring."); + if (isAttached) { + Log.i("BugsnagFlutter", "bugsnag.attach() has already been called. Ignoring."); return result; } @@ -83,7 +78,6 @@ JSONObject attach(@NonNull JSONObject args) throws Exception { notifier.setUrl(notifierJson.getString("url")); notifier.setDependencies(Collections.singletonList(new Notifier())); - isAnyAttached = true; isAttached = true; return result; } @@ -117,6 +111,7 @@ Void start(@NonNull JSONObject args) throws Exception { configuration.setMaxBreadcrumbs(args.optInt("maxBreadcrumbs", configuration.getMaxBreadcrumbs())); configuration.setMaxPersistedEvents(args.optInt("maxPersistedEvents", configuration.getMaxPersistedEvents())); configuration.setMaxPersistedSessions(args.optInt("maxPersistedSessions", configuration.getMaxPersistedSessions())); + configuration.setMaxStringValueLength(args.optInt("maxStringValueLength", configuration.getMaxStringValueLength())); configuration.setReleaseStage(args.optString("releaseStage", configuration.getReleaseStage())); configuration.setPersistUser(args.optBoolean("persistUser", configuration.getPersistUser())); diff --git a/packages/bugsnag_flutter/ios/Classes/BugsnagFlutterPlugin.m b/packages/bugsnag_flutter/ios/Classes/BugsnagFlutterPlugin.m index 7b9e6719..caea782e 100644 --- a/packages/bugsnag_flutter/ios/Classes/BugsnagFlutterPlugin.m +++ b/packages/bugsnag_flutter/ios/Classes/BugsnagFlutterPlugin.m @@ -7,6 +7,14 @@ #import #import +// Constructs a key path, with a compile-time check in DEBUG builds. +// https://pspdfkit.com/blog/2017/even-swiftier-objective-c/#checked-keypaths +#if defined(DEBUG) && DEBUG +#define BSG_KEYPATH(object, property) ((void)(NO && ((void)object.property, NO)), @ #property) +#else +#define BSG_KEYPATH(object, property) @ #property +#endif + // Will be nil in debug builds because they not contain any Dart code (App.framework) static NSString *DartCodeBuildId; @@ -59,7 +67,6 @@ @interface BugsnagStackframe (BugsnagFlutterPlugin) @interface BugsnagFlutterPlugin () -@property (nonatomic, getter=isAttached) BOOL attached; @property (nonatomic, getter=isStarted) BOOL started; @property (nullable, nonatomic) NSArray *projectPackages; @@ -199,10 +206,6 @@ - (NSDictionary *)getMetadata:(NSDictionary *)arguments { } - (NSDictionary *)attach:(NSDictionary *)arguments { - if (self.isAttached) { - [NSException raise:NSInternalInconsistencyException format:@"bugsnag.attach() may not be called more than once"]; - } - NSDictionary *result = @{ @"config": @{ @"enabledErrorTypes": @{ @@ -211,9 +214,9 @@ - (NSDictionary *)attach:(NSDictionary *)arguments { } }; - static BOOL isAnyAttached; - if (isAnyAttached) { - NSLog(@"bugsnag.attach() was called from a previous Flutter context. Ignoring."); + static BOOL isAttached; + if (isAttached) { + NSLog(@"bugsnag.attach() has already been called. Ignoring."); return result; } @@ -230,8 +233,7 @@ - (NSDictionary *)attach:(NSDictionary *)arguments { self.projectPackages = BugsnagFlutterConfiguration.projectPackages; - isAnyAttached = YES; - self.attached = YES; + isAttached = YES; return result; } @@ -253,20 +255,21 @@ - (void)start:(NSDictionary *)arguments { BugsnagConfiguration *configuration = [BugsnagConfiguration loadConfig]; - for (NSString *key in @[@"apiKey", - @"appHangThresholdMillis", - @"appType", - @"appVersion", - @"autoDetectErrors", - @"autoTrackSessions", - @"bundleVersion", - @"context", - @"launchDurationMillis", - @"maxBreadcrumbs", - @"maxPersistedEvents", - @"maxPersistedSessions", - @"releaseStage", - @"sendLaunchCrashesSynchronously"]) { + for (NSString *key in @[BSG_KEYPATH(configuration, apiKey), + BSG_KEYPATH(configuration, appHangThresholdMillis), + BSG_KEYPATH(configuration, appType), + BSG_KEYPATH(configuration, appVersion), + BSG_KEYPATH(configuration, autoDetectErrors), + BSG_KEYPATH(configuration, autoTrackSessions), + BSG_KEYPATH(configuration, bundleVersion), + BSG_KEYPATH(configuration, context), + BSG_KEYPATH(configuration, launchDurationMillis), + BSG_KEYPATH(configuration, maxBreadcrumbs), + BSG_KEYPATH(configuration, maxPersistedEvents), + BSG_KEYPATH(configuration, maxPersistedSessions), + BSG_KEYPATH(configuration, maxStringValueLength), + BSG_KEYPATH(configuration, releaseStage), + BSG_KEYPATH(configuration, sendLaunchCrashesSynchronously)]) { id value = arguments[key]; if (value && value != [NSNull null]) { [configuration setValue:value forKey:key]; diff --git a/packages/bugsnag_flutter/lib/src/client.dart b/packages/bugsnag_flutter/lib/src/client.dart index 59da8f53..e75c2a1f 100644 --- a/packages/bugsnag_flutter/lib/src/client.dart +++ b/packages/bugsnag_flutter/lib/src/client.dart @@ -17,7 +17,7 @@ import 'model.dart'; final _notifier = { 'name': 'Flutter Bugsnag Notifier', 'url': 'https://github.com/bugsnag/bugsnag-flutter', - 'version': '2.3.0' + 'version': '2.4.0' }; abstract class BugsnagClient { @@ -669,6 +669,7 @@ class Bugsnag extends BugsnagClient with DelegateClient { int maxBreadcrumbs = 50, int maxPersistedSessions = 128, int maxPersistedEvents = 32, + int maxStringValueLength = 10000, bool autoTrackSessions = true, bool autoDetectErrors = true, BugsnagThreadSendPolicy sendThreads = BugsnagThreadSendPolicy.always, @@ -716,6 +717,7 @@ class Bugsnag extends BugsnagClient with DelegateClient { 'maxBreadcrumbs': maxBreadcrumbs, 'maxPersistedSessions': maxPersistedSessions, 'maxPersistedEvents': maxPersistedEvents, + 'maxStringValueLength': maxStringValueLength, 'autoTrackSessions': autoTrackSessions, 'autoDetectErrors': autoDetectErrors, 'sendThreads': sendThreads.toName(), diff --git a/packages/bugsnag_flutter/pubspec.yaml b/packages/bugsnag_flutter/pubspec.yaml index bbf3ad44..2c6c4193 100644 --- a/packages/bugsnag_flutter/pubspec.yaml +++ b/packages/bugsnag_flutter/pubspec.yaml @@ -1,6 +1,6 @@ name: bugsnag_flutter description: Bugsnag crash monitoring and reporting tool for Flutter apps -version: 2.3.0 +version: 2.4.0 homepage: https://www.bugsnag.com/ documentation: https://docs.bugsnag.com/platforms/flutter/ repository: https://github.com/bugsnag/bugsnag-flutter