fractalup_radar_flutter 0.2.1
fractalup_radar_flutter: ^0.2.1 copied to clipboard
Production observability SDK for Flutter with errors, logs, metrics, RUM, distributed tracing, privacy controls, and offline delivery.
FractalUp Radar Flutter #
FractalUp Radar captures Flutter errors, logs, metrics, RUM, navigation, network performance, and distributed traces across Android, iOS, Linux, macOS, web, and Windows.
flutter pub add fractalup_radar_flutter
1. Install and Initialize #
Configure FractalUp once in main.dart before runApp.
import 'package:flutter/material.dart';
import 'package:fractalup_radar_flutter/fractalup_radar_flutter.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await FractalUpFlutter.init((options) {
options.ingestionKey = const String.fromEnvironment(
'FRACTALUP_RADAR_INGESTION_KEY',
);
options.environment = const String.fromEnvironment('FRACTALUP_RADAR_ENV');
options.serviceName = 'my-flutter-app';
options.autoInstrumentation = true;
options.firstPartyHosts = {'api.example.com'};
options.requestHeadersProvider = () => apiClient.currentHeaders;
}, appRunner: () => runApp(const MyApp()));
}
autoInstrumentation enables Flutter/platform error capture, async app-runner zone error capture, app lifecycle events, durable queued delivery, and runtime/app/device context on every payload. Use appRunner with FractalUpFlutter.init(...) when you want zone-level async error capture around runApp.
Flutter apps still need one-time wiring for navigation and HTTP clients:
MaterialApp(
navigatorObservers: [FractalUp.navigatorObserver],
home: const AppHome(),
);
final api = FractalUp.httpClient();
firstPartyHosts controls where distributed trace headers are injected. requestHeadersProvider is optional but recommended. Point it at the app's API/auth client so manual logs and automatic Flutter errors include safe request context. Authorization, cookies, API keys, session tokens, secrets, and passwords are redacted before sending.
2. Build With Environment and Key #
Use one ingestion key per app per environment.
Development:
flutter run \
--dart-define=FRACTALUP_RADAR_ENV=dev \
--dart-define=FRACTALUP_RADAR_INGESTION_KEY=fractalup_dev_xxx
Stage:
flutter build apk \
--dart-define=FRACTALUP_RADAR_ENV=stage \
--dart-define=FRACTALUP_RADAR_INGESTION_KEY=fractalup_stage_xxx
Production:
flutter build appbundle \
--dart-define=FRACTALUP_RADAR_ENV=prod \
--dart-define=FRACTALUP_RADAR_INGESTION_KEY=fractalup_prod_xxx
FRACTALUP_RADAR_ENV accepts dev, stage, and prod.
| Environment | Endpoint | Source ID |
|---|---|---|
dev |
https://api-eu-dev.fractalup.com |
dev |
stage |
https://api-eu-stage.fractalup.com |
stage |
prod |
https://api-eu.fractalup.com |
prod-eu1 |
Optional build-time values:
FRACTALUP_RADAR_SERVICE_NAMEFRACTALUP_RADAR_ENDPOINTFRACTALUP_RADAR_SOURCE_IDFRACTALUP_RADAR_RELEASEFRACTALUP_RADAR_APP_NAME
3. Send Manual Events #
await FractalUp.debug('debug.panel.opened', data: {
'screen': 'settings',
});
await FractalUp.info('profile.opened', data: {
'screen': 'profile',
});
await FractalUp.warning('network.retry', data: {
'attempt': 2,
});
await FractalUp.error('payment.failed', data: {
'provider': 'stripe',
'status_code': 402,
});
await FractalUp.fatal('checkout.unrecoverable', data: {
'step': 'payment_confirmation',
});
Use tags for low-cardinality filters:
await FractalUp.error(
'payment.failed',
data: {'status_code': 402},
tags: {'feature': 'checkout'},
);
Use requestHeaders only when overriding the configured provider for one specific failed request:
await FractalUp.error(
'api.request.failed',
data: {'status_code': response.statusCode},
tags: {'feature': 'checkout'},
requestHeaders: response.request?.headers ?? const {},
);
4. Capture Exceptions #
try {
await submitPayment();
} catch (error, stackTrace) {
await FractalUp.captureException(
error,
stackTrace: stackTrace,
data: {'screen': 'checkout'},
tags: {'feature': 'payments'},
);
}
With installErrorHooks: true, uncaught Flutter framework and platform dispatcher errors are captured automatically.
5. Fast Migration #
For existing exception/event instrumentation, keep the call shape and use FractalUp names after a mass replacement.
await FractalUpFlutter.init((options) {
options.ingestionKey = const String.fromEnvironment(
'FRACTALUP_RADAR_INGESTION_KEY',
);
options.environment = const String.fromEnvironment('FRACTALUP_RADAR_ENV');
options.serviceName = 'my-flutter-app';
}, appRunner: () => runApp(const MyApp()));
await FractalUp.configureScope((scope) {
scope.setTag('feature', 'checkout');
scope.setExtra('screen', 'checkout');
scope.setUser(FractalUpUser(id: user.id, email: user.email));
});
await FractalUp.captureException(
error,
stackTrace: stackTrace,
);
await FractalUp.captureMessage(
'Checkout opened',
level: FractalUpLevel.info,
);
The visible API stays FractalUp while preserving the familiar migration concepts: scope, tags, extras, user, breadcrumbs, exception capture, messages, and levels.
Setup-only exception-monitoring migration #
Existing application instrumentation can keep its call shapes after replacing
the previous SDK namespace with FractalUp. Only initialization must be
changed to provide the FractalUp ingestion key and service configuration.
The compatibility contract includes:
FractalUpFlutter.initand common Flutter optionsFractalUp.captureEvent,captureException,captureMessage, and feedback- scope, users, tags, contexts, breadcrumbs, attributes, and attachments
FractalUpWidgetandFractalUpNavigatorObserver- transactions, child spans, callback spans, and trace identifiers
- structured logger, formatted logger, metrics, and feature flags
- lifecycle methods, screenshot request API, and app-hang control API
await FractalUpFlutter.init((options) {
options.ingestionKey = const String.fromEnvironment(
'FRACTALUP_RADAR_INGESTION_KEY',
);
options.environment = const String.fromEnvironment('FRACTALUP_RADAR_ENV');
options.serviceName = 'my-flutter-app';
options.tracesSampleRate = 0.2;
options.enableLogs = true;
options.enableMetrics = true;
}, appRunner: () {
runApp(const FractalUpWidget(child: MyApp()));
});
This is source compatibility for application-facing Dart and Flutter APIs. Native crash engines, native symbol processing, continuous profiling, real screenshot/view-hierarchy attachments, app-hang/ANR engines, frame tracking, and session replay require dedicated platform implementations and are not silently emulated.
6. Logs, Metrics, Sessions, and Mobile-Agent Style Calls #
Global attributes are attached to future events, logs, metrics, and compatibility-facade calls:
FractalUp.startSession(id: sessionId);
FractalUp.setAttribute('screen', 'checkout');
FractalUp.incrementAttribute('retry_count');
await FractalUp.logger.warn(
'Payment latency high',
event: 'checkout.payment.latency',
attributes: {'duration_ms': 1250},
tags: {'feature': 'payments'},
);
await FractalUp.metric(
'checkout.duration',
category: 'Checkout',
value: 321,
);
For mobile-agent style migrations, keep the call shape and replace the visible SDK name with FractalUp:
await FractalUpMobile.instance.startAgent(Config(
accessToken: const String.fromEnvironment('FRACTALUP_RADAR_INGESTION_KEY'),
environment: const String.fromEnvironment('FRACTALUP_RADAR_ENV'),
serviceName: 'my-flutter-app',
));
await FractalUpMobile.instance.setUserId(user.id);
await FractalUpMobile.instance.setAttribute('cart_value', 99.5);
await FractalUpMobile.instance.recordCustomEvent(
'Checkout',
eventName: 'Payment Failed',
eventAttributes: {'provider': 'stripe'},
);
await FractalUpMobile.instance.recordMetric(
'checkout.duration',
'Checkout',
value: 321,
valueUnit: MetricUnit.MILLISECONDS,
);
All of these APIs normalize into the same FractalUp ingestion payload with session, trace, service, environment, user, tags, attributes, and safe request context.
The FractalUp.metrics facade aggregates counters, gauges, and distributions
locally for ten seconds by default. FractalUp.flush() sends pending metric
aggregations and queued events. Use FractalUp.metric(...) when an individual
metric event must be sent immediately.
7. Setup-Only Mobile-Agent Migration #
For an existing mobile-agent integration, replace the dependency/imports and agent class once. Existing calls such as recordError, recordCustomEvent, recordMetric, setUserId, attributes, breadcrumbs, interactions, network notices, and logging keep the same method and parameter shapes.
Use these FractalUp imports:
import 'package:fractalup_radar_flutter/config.dart';
import 'package:fractalup_radar_flutter/fractalup_mobile.dart';
import 'package:fractalup_radar_flutter/loglevel.dart';
import 'package:fractalup_radar_flutter/metricunit.dart';
import 'package:fractalup_radar_flutter/network_failure.dart';
Initialize once:
final config = Config(
accessToken: const String.fromEnvironment(
'FRACTALUP_RADAR_INGESTION_KEY',
),
environment: const String.fromEnvironment('FRACTALUP_RADAR_ENV'),
serviceName: 'my-flutter-app',
crashReportingEnabled: true,
httpInstrumentationEnabled: true,
offlineStorageEnabled: true,
distributedTracingEnabled: true,
);
await FractalUpMobile.instance.start(
config,
() => runApp(const MyApp()),
);
After that setup, existing instrumentation keeps its call shape:
FractalUpMobile.instance.recordError(error, stackTrace);
await FractalUpMobile.instance.recordCustomEvent(
'Checkout',
eventName: 'Payment Failed',
eventAttributes: {'provider': 'stripe'},
);
await FractalUpMobile.instance.recordMetric(
'checkout.duration',
'Checkout',
value: 321,
valueUnit: MetricUnit.MILLISECONDS,
);
Optional compatibility imports are also available for navigation, raw dart:io HTTP clients, global HTTP overrides, trace constants, and version metadata:
import 'package:fractalup_radar_flutter/fractalup_navigation_observer.dart';
import 'package:fractalup_radar_flutter/fractalup_http_client.dart';
import 'package:fractalup_radar_flutter/fractalup_http_overrides.dart';
import 'package:fractalup_radar_flutter/fractalup_dt_trace.dart';
import 'package:fractalup_radar_flutter/version.dart';
8. RUM Views, Actions, and HTTP Tracking #
Track screens automatically with the navigation observer:
MaterialApp(
navigatorObservers: [
FractalUp.navigatorObserver,
],
home: const AppHome(),
);
Track RUM views and user actions manually when needed:
await FractalUp.rum.startView('/checkout', 'Checkout');
await FractalUp.rum.addAction(
RumActionType.tap,
'Pay button',
{'button.id': 'pay'},
);
await FractalUp.rum.stopView('/checkout');
Wrap package:http clients to capture resources and inject W3C trace headers:
final client = FractalUp.httpClient();
final response = await client.get(
Uri.parse('https://api.example.com/pay'),
);
Each tracked request emits resource start/finish events with method, URL, status code, duration, response size, session id, and trace context. Use FractalUpHttpClient directly only when a specific client needs custom attributes or its own first-party host list.
9. Offline Queue #
Enable persisted queued events when mobile delivery should survive process restarts:
FractalUp.configureFromEnvironment(
serviceName: 'my-flutter-app',
persistQueuedEvents: true,
maxPersistedQueuedEvents: 500,
maxPersistedQueueBytes: 2 * 1024 * 1024,
);
Mobile-agent style setup enables offline storage by default. Set offlineStorageEnabled: false to disable it.
await FractalUpMobile.instance.startAgent(Config(
accessToken: const String.fromEnvironment('FRACTALUP_RADAR_INGESTION_KEY'),
offlineStorageEnabled: true,
));
10. Sampling and Privacy Hooks #
Use sampling to control event volume and beforeSend for final payload filtering:
FractalUp.configureFromEnvironment(
serviceName: 'my-flutter-app',
sampleRate: 1.0,
logSampleRate: 0.25,
rumSampleRate: 0.5,
networkSampleRate: 0.5,
beforeSend: (payload) {
if (payload['event'] == 'debug.noisy_event') {
return null;
}
return payload;
},
);
URL query values are redacted by default in event attributes, contexts, RUM resources, and persisted queue records.
FractalUp.configureFromEnvironment(
serviceName: 'my-flutter-app',
redactUrlQueryParameters: true,
);
11. Attach Current User #
After login:
FractalUp.setUser(userId: user.id);
After logout:
FractalUp.clearUser();
Optional customer-side account grouping:
FractalUp.setUser(
userId: user.id,
tenantId: account.id,
);
tenantId is observability metadata only. The ingestion key already identifies the FractalUp customer/project on the backend.
12. Production Delivery Controls #
The defaults are designed to protect the host app and control ingestion cost:
- Error deduplication uses a bounded 30-second window.
- The client permits 600 total events and 120 error events per minute.
- Transient failures use up to three attempts with capped exponential jitter.
- HTTP
429responses honorRetry-After. - Queues, persisted storage, payload depth, collection size, strings, and total payload bytes are bounded.
- Dropped, deduplicated, and rate-limited totals are attached as client reports.
- Fatal unhandled errors mark the active session as crashed for crash-free session reporting.
Every limit is configurable through FractalupRadarOptions,
FractalUp.configureHosted, FractalUp.configureFromEnvironment, or the
matching FractalUpFlutterOptions fields.
13. Platform Wiring #
Automatic Flutter/framework errors, platform dispatcher errors, async
appRunner zone errors, startup timing, lifecycle, sessions, context, privacy,
sampling, queueing, and delivery controls require only initialization.
Flutter does not expose a reliable global hook for every router or every HTTP client. Add these once:
MaterialApp(
navigatorObservers: [FractalUp.navigatorObserver],
);
final httpClient = FractalUp.httpClient();
Raw dart:io global HTTP overrides are available for compatible VM platforms.
Browser requests, custom networking stacks, native crashes, native symbols,
continuous profiling, screenshots/view hierarchy, ANR engines, frame tracking,
and session replay require platform-specific integration and are not reported
as active unless a real implementation is installed.
14. Package Documentation and License #
pub.dev generates the package page and API reference from this repository; no separate documentation website is required.
This package is licensed under the Elastic License 2.0. See LICENSE and
NOTICE. Security reports should follow SECURITY.md.