Exception handling and logging in dart/Flutter - Talker

Stanislav Ilin - Jun 4 '22 - - Dev Community

Exceptions, Exceptions, Exceptions...
We see them constantly during development and support of Applications.

Some of them we expect, and some we haven't even thought about. The worst thing you can do as a programmer is not to think about catching and tracking errors. Let's figure out how to do it...

Exceptions handling in dart

For example, we have this code. This is a call of logic from some service.



final result = service.makeLogic();
print(result);


Enter fullscreen mode Exit fullscreen mode

What will happen if we get an error in the service?
The answer is simple: program crashes and ends with an error
Image description

Such moments should be avoided. To do this, dart has a try-catch construct.



String? result;
try {
  result = service.makeLogic();
} on Exception catch (e) {
  print(e);
}
result ??= 'Can`t get result';
print(result);
```
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/68pdxigf9o6iosf5575s.png)
In this case, the program will be able to continue execution and will terminate correctly 

## Exceptions Tracking
We've figured out how to catch bugs, but what to do with tracking and error analysis?

There is a [Crashlytics](https://firebase.google.com/products/crashlytics) service from firebase for Flutter applications.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/07031x14um8cux7cvdoz.png)

It can track errors in your Flutter application.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bb4k88s0rqc3q7fnsn3f.png)

Crashlytics, Sentry, AppsFlyer and many others. There are even projects that make their own analytical system.
In startups, these tools can change frequently. Are you want to **manually write something like this every time?**
```dart
  try {
    // your code...
  } on Exception catch (exception, stackTrace) {
    Crashlytics.instance
        .recordError(exception, stackTrace, reason: exception.message);
    Sentry.captureException(exception, stackTrace: stackTrace);
    YourOwnAnalytics.sendError(exception, stackTrace: stackTrace);
    ScaffoldMessenger.of(context)
        .showSnackBar(SnackBar(content: Text(exception.toString())));
    Logger.error('Something Service exception', exception, stackTrace);
  }
```

It looks terrible🤢
But **how we can fix this case?**

## Talker
![Image description](https://github.com/Frezyx/talker/raw/master/docs/assets/gifs/talker_big.gif?raw=true)
I present to you the stable release of my library [Talker](https://github.com/Frezyx/talker)

Talker is advanced exception handling and logging tool for dart/flutter applications.
It is a system for storing and distributing debugging information of your application.

### Get started 
You can get started at [Talker documentation site](https://frezyx.github.io/talker/guide/get-started.html)

But I'll tell you here too

For [Dart](https://dart.dev/) applications you need add **talker** dependency to your **pubspec.yaml**
```yaml
dependencies:
  talker: ^1.0.0
```

For [Flutter](https://flutter.dev/) applications you can add **talker_flutter** or **talker** dependency to your **pubspec.yaml**
```yaml
dependencies:
  talker_flutter: ^1.0.0
```

**What's difference ?**<br>
**talker_flutter** has advanced features that's convenient to use in the Flutter application
like [TalkerScreen](../guide/talker-flutter.html#TalkerScreen) or [TalkerRouteObserver](../guide/talker-flutter.html#TalkerRouteObserver)<br>
**talker** package working both for dart and flutter applications

## Easy to use
All you need for the first start is to import the dependency and create an instance of the Talker class
```dart
import 'package:talker/talker.dart';
void main(){
  final talker = Talker();
  talker.info('I`m alive 😄');
}


Enter fullscreen mode Exit fullscreen mode

You can use Talker instance everywhere in your code

Simple and concise syntax will help you with this



final talker = Talker();
// Handle exceptions and errors
try {
  // your code...
} on Exception catch (e, st) {
  talker.handle(e, st, 'Exception in ...');
}

// Make logs
talker.log('App is started'),
talker.error('App is started'),
talker.waring('App is started'),


Enter fullscreen mode Exit fullscreen mode

More examples you can get there or in GitHub

Flutter initialization

Setup Talker to listen your app uncaught exceptions in runZonedGuarded onError() callback



void main() {
  final talker = Talker();
  runZonedGuarded(
    () => runApp(BaseEample(talker: talker)),
    (Object error, StackTrace stack) {
      talker.handle(error, stack, 'Uncaught app exception');
    },
  );
}


Enter fullscreen mode Exit fullscreen mode

After such initialization, all uncaught errors and exceptions will be sent to Talker for processing

Observers

And now I will tell you how to fix the problematic situation from the beginning of the article

Using the Talker library, you can simplify error handling in several services

And now this terrible spaghetti code is replaced



  try {
    // your code...
  } on Exception catch (exception, stackTrace) {
    Crashlytics.instance
        .recordError(exception, stackTrace, reason: exception.message);
    Sentry.captureException(exception, stackTrace: stackTrace);
    YourOwnAnalytics.sendError(exception, stackTrace: stackTrace);
    ScaffoldMessenger.of(context)
        .showSnackBar(SnackBar(content: Text(exception.toString())));
    Logger.error('Something Service exception', exception, stackTrace);
  }


Enter fullscreen mode Exit fullscreen mode

To this ->



try {
  // your code...
} on Exception catch (e, st) {
    talker.handle(e, st, 'Something Service exception');
}


Enter fullscreen mode Exit fullscreen mode

To send analytics to other services, just add an observer



class ExceptionsAnalyticsTalkerObserver extends TalkerObserver {
  ExceptionsAnalyticsTalkerObserver();

  @override
  Function(TalkerException e) get onException => (e) {
        Crashlytics.instance
            .recordError(e.exception, stack: e.stackTrace, reason: e.message);
        Sentry.captureException(e.exception, stackTrace: e.stackTrace);
        YourOwnAnalytics.sendError(e.exception, stackTrace: e.stackTrace);
      };
}


Enter fullscreen mode Exit fullscreen mode

And implement this observer in talker's settings



final talker = Talker(
    observers: [
        ExceptionsAnalyticsTalkerObserver(),
    ],
);


Enter fullscreen mode Exit fullscreen mode

Now all your app exception events will come to ExceptionsAnalyticsTalkerObserver observer and will be redirected to the necessary services
Isn 't it beautiful? 😌

You can read more in Customization topic at Talker documentation site

In addition to the above, Talker can do a lot of other things. Customize logs, share a log report, etc.

I put a lot of effort and time into this package. Develop and test it for 4 months. Now I am implementing it into my existing production projects. It works great and the developers are very happy with it.

❤️I will be very pleased if you promote this project and put a star on GitHub and pub.dev

I will also be very glad if you try it in your project and report any shortcomings. For documentation, visit our personal website

Thank you very much for your attention!!!

. . . . . . . . . . . . . . . . . . . .