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_sdkgenerated first (see Monitoring SDK)- A Grafana Cloud account or a self-hosted Grafana stack with Loki and Tempo
Step 1: Generate the Brick
archipelago generate grafana_monitoring_implSkip 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:
// 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:
@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:
cd apps/<appName>
flutter test test/di/injector_test.dartThe vendor registers as an AppMonitoringVendor named MonitoringInjectorKey.grafana.
Step 5: Understand Buffering and Flush
The impl buffers locally before shipping to Grafana:
| Buffer | Interval | Max items |
|---|---|---|
| Logs | 5 s | 100 |
| Traces | 10 s | 50 |
Buffers flush at capacity, on the interval and on dispose(). To flush at once, for example before the app goes to the background:
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
- Set up New Relic for SDK-based APM with interaction tracing
- Configure Crashlytics for native crash symbolication