exception_catcher 0.1.1 copy "exception_catcher: ^0.1.1" to clipboard
exception_catcher: ^0.1.1 copied to clipboard

Flutter exception collection and reporter.

exception_catcher #

中文文档

A Flutter exception collection and reporting facade.

This package focuses on capturing, normalizing, filtering, deduplicating, and dispatching exceptions. It does not bind to any specific reporting platform. You can connect Bugly, Firebase Crashlytics, or a custom reporting service by implementing ExceptionHandler.

Features #

  • Captures Flutter framework errors from FlutterError.onError
  • Captures platform dispatcher errors from PlatformDispatcher.instance.onError
  • Captures Dart zone async errors through runAppGuarded
  • Supports manual exception recording with recordError
  • Supports app context with contextProvider
  • Supports per-report context with customContext
  • Supports breadcrumbs with Breadcrumb
  • Supports exception filtering with filter
  • Supports fingerprint-based deduplication with ExceptionDeduplicator
  • Supports dispatching reports to multiple ExceptionHandler instances

Project structure #

lib/
├── exception_catcher.dart                 # Public export entry
└── src/
    ├── exception_catcher.dart             # Core facade for initialization, capture, and dispatch
    ├── config/
    │   └── exception_catcher_config.dart  # Configuration definitions
    ├── deduplication/
    │   └── exception_deduplicator.dart    # Exception fingerprint deduplication
    ├── handler/
    │   ├── exception_handler.dart         # Reporting handler interface
    │   ├── console_exception_handler.dart # Console output handler
    │   └── memory_exception_handler.dart  # In-memory handler for tests
    ├── mode/
    │   ├── report_mode.dart               # Report mode interface
    │   └── silent_report_mode.dart        # Silent report mode
    └── model/
        ├── breadcrumb.dart                # Breadcrumb model
        ├── exception_report.dart          # Standard exception report model
        └── exception_types.dart           # Exception source and severity enums

Core concepts #

ExceptionCatcher #

ExceptionCatcher is the main entry point.

It is responsible for:

  • Installing FlutterError.onError
  • Installing PlatformDispatcher.instance.onError
  • Capturing async errors with runZonedGuarded
  • Creating standardized ExceptionReport objects
  • Running filtering, deduplication, and report mode checks
  • Dispatching reports to multiple ExceptionHandler instances
  • Keeping breadcrumbs before an exception occurs

Common methods:

Method Description
initialize() Initializes configuration and installs global error hooks
runAppGuarded() Starts the app inside a guarded zone
recordError() Records an exception manually
addBreadcrumb() Adds a breadcrumb
clearBreadcrumbs() Clears breadcrumbs
dispose() Disposes handlers and resets runtime state

ExceptionCatcherConfig #

ExceptionCatcherConfig controls capture and dispatch behavior.

It configures:

  • Which ExceptionHandler instances to use
  • Whether to capture Flutter framework errors
  • Whether to capture PlatformDispatcher errors
  • Whether to forward errors to existing handlers
  • Whether to filter reports
  • Whether to deduplicate reports
  • Handler timeout
  • Maximum breadcrumb count
  • App context provider contextProvider

ExceptionReport #

ExceptionReport is the standard data model generated for every exception.

It contains:

  • Exception message message
  • Exception type errorType
  • Stack trace stackTrace
  • Source source
  • Severity severity
  • Flutter error context
  • App context appContext
  • Custom context customContext
  • Breadcrumbs breadcrumbs

Use toJson() to create uploadable data. Use redact() to redact sensitive fields.

ExceptionHandler #

ExceptionHandler is the integration point for reporting platforms.

Built-in handlers:

  • ConsoleExceptionHandler: prints reports during development
  • MemoryExceptionHandler: stores reports in memory for tests

In production, implement a custom handler and upload ExceptionReport to Bugly, Firebase Crashlytics, or your own service.

ExceptionDeduplicator #

ExceptionDeduplicator skips repeated reports by exception fingerprint and time window.

The fingerprint is generated from exception type, message, and the first stack trace lines.

The default deduplication window is 1 minute.

ReportMode #

ReportMode controls whether a report should continue to be handled.

The default SilentReportMode allows reports without showing UI or blocking app flow.

Installation #

Add the dependency:

dependencies:
  exception_catcher: ^0.1.0

Then run:

flutter pub get

Quick start #

Use ExceptionCatcher.runAppGuarded in your app entry point.

await ExceptionCatcher.runAppGuarded(
  () async {
    WidgetsFlutterBinding.ensureInitialized();
    await preInit();
    runApp(const App());
  },
  config: ExceptionCatcherConfig(
    handlers: <ExceptionHandler>[
      ConsoleExceptionHandler(includeStackTrace: true),
    ],
    contextProvider: () async => <String, Object?>{
      'env': 'dev',
      'appVersion': '1.0.0',
      'buildNumber': '1',
    },
  ),
);

App integration #

Recommended startup order:

  1. Call ExceptionCatcher.runAppGuarded() from main()
  2. Call WidgetsFlutterBinding.ensureInitialized() inside its callback
  3. Initialize app dependencies inside the same callback
  4. Call runApp() inside the same callback

runAppGuarded uses runZonedGuarded internally. Keep WidgetsFlutterBinding.ensureInitialized() and runApp() in the same callback to avoid Flutter zone mismatch errors.

Avoid setting these again manually:

  • FlutterError.onError
  • PlatformDispatcher.instance.onError
  • Outer runZonedGuarded

They are handled by ExceptionCatcher.

Manual recording #

Callers can record exceptions manually:

try {
  await doSomething();
} catch (error, stackTrace) {
  await ExceptionCatcher.recordError(
    error,
    stackTrace,
    source: ExceptionSource.manual,
    customContext: <String, Object?>{
      'module': 'checkout',
      'action': 'submit',
    },
  );
  rethrow;
}

Record important actions before an exception occurs:

ExceptionCatcher.addBreadcrumb(
  'open settings page',
  category: 'navigation',
  data: <String, Object?>{
    'from': 'home',
  },
);

Clear breadcrumbs:

ExceptionCatcher.clearBreadcrumbs();

Custom handler #

Extend ExceptionHandler to integrate a reporting platform:

class CustomExceptionHandler extends ExceptionHandler {
  @override
  String get name => 'custom';

  @override
  Future<void> initialize() async {
    // Initialize SDK.
  }

  @override
  Future<HandlerResult> handle(ExceptionReport report) async {
    final payload = report.redact(<String>{
      'password',
      'token',
      'code',
    }).toJson();

    await upload(payload);
    return const HandlerResult.handled();
  }

  Future<void> upload(Map<String, Object?> payload) async {}
}

Configuration #

Field Description Default
handlers Exception handlers ConsoleExceptionHandler()
reportMode Report mode SilentReportMode()
filter Exception filter null
deduplicator Exception deduplicator ExceptionDeduplicator()
contextProvider App context provider null
onHandlerError Handler failure callback null
handlerTimeout Single handler timeout 10s
maxBreadcrumbs Maximum breadcrumb count 50
handleFlutterErrors Capture Flutter framework errors true
handlePlatformDispatcherErrors Capture PlatformDispatcher errors true
forwardToExistingHandlers Forward to existing error handlers true
platformDispatcherErrorResult PlatformDispatcher error result true

Exception sources #

Enum Description
ExceptionSource.manual Manually recorded exception
ExceptionSource.flutter Flutter framework exception
ExceptionSource.platformDispatcher PlatformDispatcher exception
ExceptionSource.zone Dart zone async exception
ExceptionSource.network Manually recorded network-chain exception

Built-in handlers #

ConsoleExceptionHandler #

Prints reports to the console during development.

const ConsoleExceptionHandler(includeStackTrace: true)

MemoryExceptionHandler #

Stores reports in memory for tests.

final handler = MemoryExceptionHandler();

Redaction #

ExceptionReport.redact() replaces values for matching keys:

final safeReport = report.redact(<String>{
  'password',
  'token',
  'verificationCode',
});

Production handlers should redact sensitive data before uploading reports.

Testing #

Run tests:

flutter test

Run analysis:

flutter analyze

Example #

The repository includes a minimal Flutter example app:

example/
├── pubspec.yaml
└── lib/
    └── main.dart

The example shows how to:

  • Initialize and start the app with runAppGuarded()
  • Print reports with ConsoleExceptionHandler
  • Add app context with contextProvider
  • Add breadcrumbs with addBreadcrumb()
  • Record handled exceptions with recordError()
  • Verify zone capture with an unhandled async exception

Run the example:

cd example
flutter pub get
flutter run

Scope #

exception_catcher does not provide:

  • Error dialogs or page-level error UI
  • Built-in reporting platform SDK bindings
  • Local persistent queues
  • Offline retry strategy
  • Automatic sensitive field detection

Implement these in a custom ExceptionHandler or the application layer.

0
likes
150
points
29
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Flutter exception collection and reporter.

Repository (GitHub)
View/report issues

Topics

#flutter #exception-handling #crash-reporting

License

MIT (license)

Dependencies

flutter

More

Packages that depend on exception_catcher