Skip to content
Back to archipelago.banuacoder.com

Monitoring Implementations

How to send Flutter traces and logs to Grafana with monitoring_sdk ​

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

Generate the Grafana vendor, configure Grafana Cloud or a self-hosted stack through GrafanaRegisterModule, and learn how log and trace buffering works.

What you'll learn ​

  • Generating the Grafana monitoring implementation brick
  • Configuring Grafana Cloud or a self-hosted stack via GrafanaRegisterModule
  • Understanding the built-in log and trace buffering behaviour

Prerequisites ​

  • monitoring_sdk generated first (see Monitoring SDK)
  • A Grafana Cloud account or a self-hosted Grafana stack with Loki and Tempo

Step 1: Generate the Brick ​

bash
archipelago generate grafana_monitoring_impl

Skip this step if you chose grafana in monitoringVendors at project creation.

The prompts are:

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

The brick generates in infrastructure/grafana_monitoring_impl/. Unlike the Crashlytics or Sentry bricks, this impl uses plain HTTP. No vendor SDK joins your dependency tree.

Step 2: Retrieve Grafana Credentials ​

Grafana Cloud: Navigate to your Stack → Details → Access Policies. Create a policy with logs:write and traces:write scopes. Copy the Instance ID and the API key.

Self-hosted: You need the Loki push endpoint and the Tempo OTLP HTTP endpoint, plus basic auth credentials if your instance requires them.

Step 3: Override GrafanaRegisterModule ​

Grafana Cloud:

dart
// apps/<appName>/lib/di/app_grafana_module.dart
@module
abstract class AppGrafanaModule extends GrafanaRegisterModule {
  @override
  @lazySingleton
  GrafanaConfig get grafanaConfig => GrafanaConfig.grafanaCloud(
    instanceId: Env.grafanaInstanceId,
    apiKey: Env.grafanaApiKey,
    serviceName: Env.appName,
    serviceVersion: Env.version,
    environment: Flavor.status.name,
  );
}

Self-hosted:

dart
@module
abstract class AppGrafanaModule extends GrafanaRegisterModule {
  @override
  @lazySingleton
  GrafanaConfig get grafanaConfig => GrafanaConfig(
    lokiEndpoint: Uri.parse(Env.lokiEndpoint),
    tempoEndpoint: Uri.parse(Env.tempoEndpoint),
    basicAuthUser: Env.grafanaUser,
    basicAuthPassword: Env.grafanaPassword,
    serviceName: Env.appName,
    serviceVersion: Env.version,
    environment: Flavor.status.name,
  );
}

Step 4: Check the Registration ​

You register nothing by hand. The post-generation hook adds the package to the host app pubspec.yaml. It registers GrafanaMonitoringImplPackageModule in lib/di/injector.dart.

The monitoring_impl fanout builds its vendor list when AppMonitoring is first resolved. Every vendor module must run before that. Install order does not decide the injector order. The hook rebuilds the entries from the package manifests in dependency order. Generate monitoring_sdk first when you install standalone, because the vendor imports monitoring_api.

Run the composition-root test to confirm the wiring:

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

The vendor registers as an AppMonitoringVendor named MonitoringInjectorKey.grafana.

Step 5: Understand Buffering and Flush ​

The impl buffers locally before shipping to Grafana:

BufferIntervalMax items
Logs5 s100
Traces10 s50

Buffers flush at capacity, on the interval and on dispose(). To flush at once, for example before the app goes to the background:

dart
final grafana = getIt<AppMonitoringVendor>(
  instanceName: MonitoringInjectorKey.grafana,
);
grafana.flushLogs();
grafana.flushTraces();

AppMonitoring sends nothing until diagnostics consent is granted. If the user withdraws consent, the vendor stops its timers and discards both buffers without sending them. Granting again starts collection from empty.

Logs ship to Loki at /loki/api/v1/push. Traces ship to Tempo at /api/traces in OTLP JSON format.

Next Steps ​