Exception handling and logging in dart/Flutter - Talker
Tags: flutter, dart, opensource, android
Published: 2022-06-04 12:12:59

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.

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

What will happen if we get an error in the service?
The answer is simple: program crashes and ends with an error
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g734bzowrsagbjt0888n.png)

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

```dart
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 😄');
}
```
You can use Talker instance everywhere in your code<br>
Simple and concise syntax will help you with this
```dart
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'),
```
More examples you can get [there](../guide/examples) or in [GitHub](https://github.com/Frezyx/talker/blob/master/packages/talker/example/talker_example.dart) 

## Flutter initialization
Setup Talker to listen your app uncaught exceptions in [runZonedGuarded](https://api.flutter.dev/flutter/dart-async/runZonedGuarded.html) **onError()** callback
```dart
void main() {
  final talker = Talker();
  runZonedGuarded(
    () => runApp(BaseEample(talker: talker)),
    (Object error, StackTrace stack) {
      talker.handle(error, stack, 'Uncaught app exception');
    },
  );
}
```
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
```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);
  }
```
To this -> 
```dart
try {
  // your code...
} on Exception catch (e, st) {
    talker.handle(e, st, 'Something Service exception');
}
```
To send analytics to other services, just add an observer
```dart
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);
      };
}
```
And implement this observer in talker's settings
```dart
final talker = Talker(
    observers: [
        ExceptionsAnalyticsTalkerObserver(),
    ],
);
```
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](https://frezyx.github.io/talker/guide/customization.html) topic at [Talker documentation site](https://frezyx.github.io/talker)

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](https://github.com/Frezyx/talker) and [pub.dev](https://pub.dev/packages/talker)

I will also be very glad if you try it in your project and report any shortcomings. For documentation, visit [our personal website](https://frezyx.github.io/talker/)

Thank you very much for your attention!!!