Skip to content
Back to archipelago.banuacoder.com

Infrastructure SDKs

How to add crash reporting and monitoring to a Flutter app ​

Free Reference for monitoring_sdk: every variable, option and package it generates. Command: archipelago generate monitoring_sdk

Generate the Monitoring SDK, add a vendor brick, log errors and transactions through AppMonitoring, and see how consent gating and PII scrubbing work.

What you'll learn ​

  • Generating the Monitoring SDK and adding vendor bricks
  • Using AppMonitoring for logs, errors and transactions
  • Understanding consent gating and PII scrubbing
  • Knowing what ships in release builds

Prerequisites ​

  • An existing Archipelago monorepo (see Monorepo Scaffolding)
  • A vendor account (Crashlytics, Sentry, Grafana or New Relic) for real reports

Step 1: Generate the Monitoring SDK ​

flutter_modular_monorepo always generates monitoring_sdk, even with no vendor. To add it to an older project, run:

bash
archipelago generate monitoring_sdk

The prompts are:

  • appName: your app name, for example MyApp
  • isForMonorepo: leave this as true

Or use a config file:

json
{
  "appName": "MyApp",
  "isForMonorepo": true
}
bash
archipelago generate monitoring_sdk --config monitoring_config.json

Choose vendors with monitoringVendors when you create the project. Each vendor is its own brick:

Generate monitoring_sdk before you add a vendor to an existing project. The vendor imports monitoring_api.

Step 2: Understand the Three-Package Structure ​

text
infrastructure/
├── monitoring_api/          # AppMonitoring, AppMonitoringVendor, MonitoringLevel
├── monitoring_impl/         # Fanout, consent decorator, vendor collection
│   └── lib/src/
│       ├── monitoring_fanout_impl.dart
│       ├── consent_aware_monitoring.dart
│       └── di/
└── monitoring_noop/         # Inert stub for tests or an explicit opt-out

A vendor implements AppMonitoringVendor and registers under a @Named key. MonitoringFanoutImpl sends each call to every enabled vendor. One vendor that throws does not stop the others.

With no vendor installed, AppMonitoring still works. isEnabled is false and every call does nothing.

Step 3: Check the Registration ​

The post-generation hook adds the package to the app pubspec.yaml. It registers MonitoringImplPackageModule in lib/di/injector.dart. getIt<AppMonitoring>() returns ConsentAwareMonitoring, which wraps the fanout. You never resolve the fanout directly.

Step 4: Use AppMonitoring ​

Features take AppMonitoring from monitoring_api by constructor:

dart
class PaymentRepository {
  PaymentRepository(this._monitoring);

  final AppMonitoring _monitoring;

  Future<Payment> processPayment(PaymentRequest request) async {
    _monitoring.log('Payment started', tag: 'PAY', level: MonitoringLevel.info);
    try {
      return await _monitoring.recordTransaction(
        'process_payment',
        () => _remote.process(request),
        operation: 'http.post',
      );
    } catch (e, st) {
      await _monitoring.recordError(e, st);
      rethrow;
    }
  }
}

The other methods are breadcrumb, setUserContext, clearUserContext and recordFlutterError.

ConsentAwareMonitoring checks ConsentPurpose.diagnostics on every call. Until the user grants it, nothing reaches a vendor, and initialize() does not start the vendor SDKs.

  • recordTransaction still runs your action when consent is denied. Only the report is skipped.
  • clearUserContext and dispose are never gated.
  • When the user withdraws diagnostics consent later, every vendor stops collecting and drops what it buffered. A later grant starts the vendors again.
  • recordTransaction keeps a duration_ms you pass in data. It measures one only when you give none.
  • Exception messages pass through the telemetry scrubber before they leave the device.

Step 6: Know the Global Error Handlers ​

The fanout installs no global handlers. bootstrap.dart owns FlutterError.onError and PlatformDispatcher.instance.onError. Both report through AppMonitoring, so consent gates every uncaught error.

Step 7: Release Builds ​

Monitoring ships in release builds. Crash reporting matters most in production, and the consent gate is the privacy control. The generated build_prepare.yaml has no monitoring mapping. The debug tooling (app_debugger, app_blackbox) is what the production flavor strips.

To strip monitoring from release anyway, add this mapping by hand:

yaml
build_prepare:
  mappings:
    - debug: monitoring_impl
      release: monitoring_noop

Then run dart run monorepo_toolkit build-prepare --flavor production before the build.

Step 8: Test ​

monitoring_impl needs no test prerequisite. A vendor that cannot be built in a test, such as Crashlytics without Firebase, is skipped. getIt<AppMonitoring>() still resolves. Run the composition-root test:

bash
cd apps/<appName>
flutter test test/di/injector_test.dart

Key Customization Points ​

CustomizationWhere to Change
Add a vendorGenerate its brick
Strip monitoring in releaseThe build_prepare.yaml mapping above
Scrubbing rulesThe app TelemetryScrubber from shared_consent

Next Steps ​