mirror of
https://github.com/GitJournal/GitJournal.git
synced 2025-06-30 03:19:11 +08:00
Move error reporting to its own file
* Avoid passing Flutter errors to its Zone handler, this doesn't always catch the errors * Catch the current isolate's errors. I haven't been able to test this out, but lets see.
This commit is contained in:
115
lib/error_reporting.dart
Normal file
115
lib/error_reporting.dart
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:device_info/device_info.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter_crashlytics/flutter_crashlytics.dart';
|
||||||
|
import 'package:gitjournal/app.dart';
|
||||||
|
import 'package:gitjournal/settings.dart';
|
||||||
|
import 'package:package_info/package_info.dart';
|
||||||
|
import 'package:sentry/sentry.dart';
|
||||||
|
|
||||||
|
SentryClient _sentryClient;
|
||||||
|
Future<SentryClient> _initSentry() async {
|
||||||
|
return SentryClient(
|
||||||
|
dsn: 'https://35f34dbec289435fbe16483faacf49a5@sentry.io/5168082',
|
||||||
|
environmentAttributes: await _environmentEvent,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<SentryClient> getSentryClient() async {
|
||||||
|
return _sentryClient ??= await _initSentry();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Event> get _environmentEvent async {
|
||||||
|
final packageInfo = await PackageInfo.fromPlatform();
|
||||||
|
final deviceInfoPlugin = DeviceInfoPlugin();
|
||||||
|
OperatingSystem os;
|
||||||
|
Device device;
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
final androidInfo = await deviceInfoPlugin.androidInfo;
|
||||||
|
os = OperatingSystem(
|
||||||
|
name: 'android',
|
||||||
|
version: androidInfo.version.release,
|
||||||
|
);
|
||||||
|
device = Device(
|
||||||
|
model: androidInfo.model,
|
||||||
|
manufacturer: androidInfo.manufacturer,
|
||||||
|
modelId: androidInfo.product,
|
||||||
|
);
|
||||||
|
} else if (Platform.isIOS) {
|
||||||
|
final iosInfo = await deviceInfoPlugin.iosInfo;
|
||||||
|
os = OperatingSystem(
|
||||||
|
name: iosInfo.systemName,
|
||||||
|
version: iosInfo.systemVersion,
|
||||||
|
);
|
||||||
|
device = Device(
|
||||||
|
model: iosInfo.utsname.machine,
|
||||||
|
family: iosInfo.model,
|
||||||
|
manufacturer: 'Apple',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
final environment = Event(
|
||||||
|
release: '${packageInfo.version} (${packageInfo.buildNumber})',
|
||||||
|
contexts: Contexts(
|
||||||
|
operatingSystem: os,
|
||||||
|
device: device,
|
||||||
|
app: App(
|
||||||
|
name: packageInfo.appName,
|
||||||
|
version: packageInfo.version,
|
||||||
|
build: packageInfo.buildNumber,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
void flutterOnErrorHandler(FlutterErrorDetails details) {
|
||||||
|
if (reportCrashes == true) {
|
||||||
|
// vHanda: This doesn't always call our zone error handler, why?
|
||||||
|
// Zone.current.handleUncaughtError(details.exception, details.stack);
|
||||||
|
reportError(details.exception, details.stack);
|
||||||
|
} else {
|
||||||
|
FlutterError.dumpErrorToConsole(details);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get reportCrashes => _reportCrashes ??= _initReportCrashes();
|
||||||
|
bool _reportCrashes;
|
||||||
|
bool _initReportCrashes() {
|
||||||
|
return !JournalApp.isInDebugMode && Settings.instance.collectCrashReports;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<FlutterCrashlytics> getCrashlyticsClient() async {
|
||||||
|
return _crashlytics ??= await _initCrashlytics();
|
||||||
|
}
|
||||||
|
|
||||||
|
FlutterCrashlytics _crashlytics;
|
||||||
|
Future<FlutterCrashlytics> _initCrashlytics() async {
|
||||||
|
await FlutterCrashlytics().initialize();
|
||||||
|
return FlutterCrashlytics();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> reportError(Object error, StackTrace stackTrace) async {
|
||||||
|
if (reportCrashes) {
|
||||||
|
try {
|
||||||
|
final sentry = await getSentryClient();
|
||||||
|
sentry.captureException(
|
||||||
|
exception: error,
|
||||||
|
stackTrace: stackTrace,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
print("Failed to report with Sentry: $e");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final crashlytics = await getCrashlyticsClient();
|
||||||
|
crashlytics.reportCrash(error, stackTrace, forceCrash: false);
|
||||||
|
} catch (e) {
|
||||||
|
print("Failed to report with Crashlytics: $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print("Uncaught Exception: $error");
|
||||||
|
print(stackTrace);
|
||||||
|
}
|
@ -1,10 +1,10 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:isolate';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/foundation.dart' as foundation;
|
import 'package:flutter/foundation.dart' as foundation;
|
||||||
|
|
||||||
import 'package:flutter_crashlytics/flutter_crashlytics.dart';
|
import 'package:gitjournal/error_reporting.dart';
|
||||||
import 'package:sentry/sentry.dart';
|
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
import 'package:gitjournal/app.dart';
|
import 'package:gitjournal/app.dart';
|
||||||
@ -17,35 +17,18 @@ void main() async {
|
|||||||
Settings.instance.load(pref);
|
Settings.instance.load(pref);
|
||||||
|
|
||||||
JournalApp.isInDebugMode = foundation.kDebugMode;
|
JournalApp.isInDebugMode = foundation.kDebugMode;
|
||||||
var reportCrashes =
|
FlutterError.onError = flutterOnErrorHandler;
|
||||||
!JournalApp.isInDebugMode && Settings.instance.collectCrashReports;
|
|
||||||
|
|
||||||
FlutterError.onError = (FlutterErrorDetails details) {
|
Isolate.current.addErrorListener(RawReceivePort((dynamic pair) async {
|
||||||
if (!reportCrashes) {
|
var isolateError = pair as List<dynamic>;
|
||||||
FlutterError.dumpErrorToConsole(details);
|
assert(isolateError.length == 2);
|
||||||
} else {
|
assert(isolateError.first.runtimeType == Error);
|
||||||
Zone.current.handleUncaughtError(details.exception, details.stack);
|
assert(isolateError.last.runtimeType == StackTrace);
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
print("Report Crashes: $reportCrashes");
|
await reportError(isolateError.first, isolateError.last);
|
||||||
if (reportCrashes) {
|
}).sendPort);
|
||||||
await FlutterCrashlytics().initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
var sentry = SentryClient(
|
|
||||||
dsn: 'https://35f34dbec289435fbe16483faacf49a5@sentry.io/5168082',
|
|
||||||
);
|
|
||||||
|
|
||||||
runZoned<Future<void>>(() async {
|
runZoned<Future<void>>(() async {
|
||||||
await JournalApp.main(pref);
|
await JournalApp.main(pref);
|
||||||
}, onError: (Object error, StackTrace stackTrace) async {
|
}, onError: reportError);
|
||||||
print("Uncaught Exception: " + error.toString());
|
|
||||||
print(stackTrace);
|
|
||||||
FlutterCrashlytics().reportCrash(error, stackTrace, forceCrash: false);
|
|
||||||
sentry.captureException(
|
|
||||||
exception: error,
|
|
||||||
stackTrace: stackTrace,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user