Skip to content

Commit

Permalink
Merge remote-tracking branch 'kattalo/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
ThexXTURBOXx committed May 20, 2024
2 parents f260326 + e9fee07 commit 63dfb68
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 23 deletions.
60 changes: 44 additions & 16 deletions lib/core/catcher_2.dart
Original file line number Diff line number Diff line change
Expand Up @@ -79,18 +79,21 @@ class Catcher2 implements ReportModeAction {

void _configure(GlobalKey<NavigatorState>? navigatorKey) {
_instance = this;
_initWidgetsBinding();
_configureNavigatorKey(navigatorKey);
_setupCurrentConfig();
_configureLogger();
_setupReportModeActionInReportMode();
_setupScreenshotManager();

_setupErrorHooks();

_initWidgetBindingAndRunApp();

// Loading device and application info requires that the widgets binding is
// initialized so we need to run it after we init WidgetsFlutterBinding.
_loadDeviceInfo();
_loadApplicationInfo();

_setupErrorHooks();

if (_currentConfig.handlers.isEmpty) {
_logger.warning(
'Handlers list is empty. Configure at least one handler to '
Expand Down Expand Up @@ -170,6 +173,7 @@ class Catcher2 implements ReportModeAction {
}

Future<void> _setupErrorHooks() async {
// FlutterError.onError catches SYNCHRONOUS errors for all platforms
FlutterError.onError = (details) async {
await _reportError(
details.exception,
Expand All @@ -178,14 +182,20 @@ class Catcher2 implements ReportModeAction {
);
_currentConfig.onFlutterError?.call(details);
};
PlatformDispatcher.instance.onError = (error, stack) {
_reportError(error, stack);
_currentConfig.onPlatformError?.call(error, stack);
return true;
};

// PlatformDispatcher.instance.onError catches ASYNCHRONOUS errors, but it
// does not work for web, most likely due to this issue:
// https://github.com/flutter/flutter/issues/100277
if (!kIsWeb) {
PlatformDispatcher.instance.onError = (error, stack) {
_reportError(error, stack);
_currentConfig.onPlatformError?.call(error, stack);
return true;
};
}

/// Web doesn't have Isolate error listener support
if (!ApplicationProfileManager.isWeb()) {
if (!kIsWeb) {
Isolate.current.addErrorListener(
RawReceivePort((pair) async {
final isolateError = pair as List<dynamic>;
Expand All @@ -195,14 +205,32 @@ class Catcher2 implements ReportModeAction {
);
}).sendPort,
);
}
}

void _initWidgetBindingAndRunApp() {
if (!kIsWeb) {
// This isn't web, we can just run the app, no need for runZoneGuarded
// since async errors are caught by PlatformDispatcher.instance.onError.
_initWidgetsBindingIfNeeded();
_runApp();
} else {
// Due to https://github.com/flutter/flutter/issues/100277
// this is still needed... As soon as proper error catching support
// for Web is implemented, this branch should be removed and just
// _runApp should be called, the same as in the other branch
// without the Isolate[...] stuff.
runZonedGuarded(_runApp, _reportError);
// We are in a web environment so we need runZoneGuarded to catch async
// exceptions.
unawaited(
runZonedGuarded<Future<void>>(
() async {
// It is important that we run init widgets binding inside the
// runZonedGuarded call to be able to catch the async execeptions.
_initWidgetsBindingIfNeeded();
_runApp();
},
(error, stack) {
_reportError(error, stack);
_currentConfig.onPlatformError?.call(error, stack);
},
),
);
}
}

Expand All @@ -216,7 +244,7 @@ class Catcher2 implements ReportModeAction {
}
}

void _initWidgetsBinding() {
void _initWidgetsBindingIfNeeded() {
if (ensureInitialized) {
WidgetsFlutterBinding.ensureInitialized();
}
Expand Down
26 changes: 19 additions & 7 deletions lib/handlers/sentry_handler.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import 'package:sentry/sentry.dart';
class SentryHandler extends ReportHandler {
SentryHandler(
this.sentryClient, {
this.serverName = 'Catcher 2',
this.loggerName = 'Catcher 2',
this.userContext,
this.enableDeviceParameters = true,
this.enableApplicationParameters = true,
Expand All @@ -21,6 +23,8 @@ class SentryHandler extends ReportHandler {

/// Sentry Client instance
final SentryClient sentryClient;
final String serverName;
final String loggerName;

/// User data
SentryUser? userContext;
Expand Down Expand Up @@ -66,11 +70,12 @@ class SentryHandler extends ReportHandler {
// and the code relies on File from dart:io that does not work in web
// either because we do not have access to the file system in web.
SentryAttachment? screenshotAttachment;
File? screenshotFile;
try {
if (report.screenshot != null && !kIsWeb) {
final screenshotPath = report.screenshot!.path;
final file = File(screenshotPath);
final bytes = await file.readAsBytes();
screenshotFile = File(screenshotPath);
final bytes = await screenshotFile.readAsBytes();
screenshotAttachment = SentryAttachment.fromScreenshotData(bytes);
_printLog('Created screenshot attachment');
}
Expand All @@ -86,6 +91,12 @@ class SentryHandler extends ReportHandler {
: null,
);

if (screenshotFile != null) {
// Cleanup screenshot file after submission to save space on device.
await screenshotFile.delete();
_printLog('Screenshot file removed from device (cleanup)');
}

_printLog('Logged to sentry!');
return true;
} catch (exception, stackTrace) {
Expand All @@ -98,10 +109,11 @@ class SentryHandler extends ReportHandler {
var applicationVersion = '';
final applicationParameters = report.applicationParameters;
if (applicationParameters.containsKey('appName')) {
applicationVersion += (applicationParameters['appName'] as String?)!;
applicationVersion +=
(applicationParameters['appName'] as String?)!.toLowerCase();
}
if (applicationParameters.containsKey('version')) {
applicationVersion += " ${applicationParameters["version"]}";
applicationVersion += "@${applicationParameters["version"]}";
}
if (applicationVersion.isEmpty) {
applicationVersion = '?';
Expand All @@ -111,12 +123,12 @@ class SentryHandler extends ReportHandler {

SentryEvent buildEvent(Report report, Map<String, dynamic> tags) =>
SentryEvent(
logger: 'Catcher 2',
serverName: 'Catcher 2',
logger: loggerName,
serverName: serverName,
release: customRelease ?? _getApplicationVersion(report),
environment: customEnvironment ??
(report.applicationParameters['environment'] as String?),
message: const SentryMessage('Error handled by Catcher 2'),
message: SentryMessage(report.error.toString()),
throwable: report.error,
level: SentryLevel.error,
culprit: '',
Expand Down
3 changes: 3 additions & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ version: 1.3.0
homepage: https://github.com/ThexXTURBOXx/catcher_2
repository: https://github.com/ThexXTURBOXx/catcher_2
issue_tracker: https://github.com/ThexXTURBOXx/catcher_2/issues

funding:
- https://github.com/sponsors/ThexXTURBOXx

screenshots:
- description: 'The catcher_2 logo'
path: screenshots/logo.png
Expand All @@ -15,6 +17,7 @@ screenshots:
path: screenshots/3.png
- description: 'catcher_2 in action with dialogs'
path: screenshots/6.png

topics:
- analysis
- errors
Expand Down

0 comments on commit 63dfb68

Please sign in to comment.