Error Reporting in Flutter

Debug

bug

code quality

flutter

Purpose

Flutter is a Dart-based cross-platform app development framework that has been gaining traction in the mobile development community and has been lauded for its animation capabilities. It went from being a playground framework to a seriously considered option for production apps. How does Flutter stand in terms of industrial standards for app development and exploitation?

TLDR

  • You can use Sentry to report errors from your Flutter projects

  • All error reporting services as of today need manual reporting in your Dart code

  • Flutter considers by default all errors as non-fatal

  • Native stack traces are not transmitted to the Dart error handlers


Crash reporting at a glance

When an app starts its life on the app stores, the most critical events that negatively affects the app’s quality are its crashes. As you reach for a high quality standard, you need equally reliable ways to:

  • count crashes;

  • collect helpful details to diagnose them.

Tools such as Sentry and Crashlytics have become a golden standard for native and cross platform apps, as they:

  • provide detailed stack traces at the different app software layers (native, UI code…)

  • aggregate crashes data in easy-to-visualize ways

Let’s see if we can reach these objectives with Flutter

General setup

Native errors get sent to Sentry as well, although with a less detailed stacktrace that a thrown FlutterError.

It is possible to get any error reporting service (e.g. Sentry, Crashlytics, Datadog…) running within your app, it can be used the following way:

  • Wrap your app inside a Zone, which is basically a try/catch block that catches uncaught asynchronous errors

  • In the runZoned call, pass your errorHandler which will report all app errors to your reporting service

The code should now look like this:

// In your main.dart file
import 'dart:async';
/* Some imports and code */
void main() async {
runZoned<Future<void>>(() async {
runApp(MyApp());
}, onError: (error, stackTrace) {/* Handle your error here */});

Calling an error handling service

The Flutter team has provided an excellent guide on how to setup Sentry on your app here . You can easily setup crash reporting to Sentry with a Dart HTTP Sentry client that has been developed by the Flutter team themselves.

  • Get a DSN from sentry.io

  • Follow the guide mentioned above to create the zone and initialize / call the Sentry service. Your code should look like this:

import 'dart:async'
import 'package:sentry/sentry.dart';
final SentryClient _sentry = new SentryClient(dsn:"EXAMPLE_DSN"); // Replace by your own DSN

Future<Null> _reportError(dynamic error, dynamic stackTrace) async {
print('Caught error: $error');

print('Reporting to Sentry.io...');

final SentryResponse response = await _sentry.captureException(
exception: error,
stackTrace: stackTrace,
);

if (response.isSuccessful) {
print('Success! Event ID: ${response.eventId}');
} else {
print('Failed to report to Sentry.io: ${response.error}');
}
}
void main() async {
runZoned(() async {
runApp(MyApp());
}, onError: _reportError);
}

You should see something like this on your Sentry dashboard, in this example calling a non-existing native method. Notice that Sentry by default reports events as errors.

 

Sentry

 

Note: Crashlytics support status

There is an early stage Crashlytics pub package that you can setup following this guide. However, I was not able to see errors on my Crashlytics after 36h, so for now I rely on Sentry to monitor app errors and crashes. If someone managed to make it work, do not hesitate to reach out to me. I have put up an example repo here in case you want to check it out.

Note: Flutter errors are non-fatal

When running in dev mode or using a Zone, Flutter catches all kinds of errors and does not let the app crash. That’s why handling errors Flutter-side will only log non-fatal errors. This is an ongoing issue in the official Flutter Crashlytics plugin, although it is possible to force a crash if you use the non-official Crashlytics plugin through the forceCrash option