observatory 2.0.0 copy "observatory: ^2.0.0" to clipboard
observatory: ^2.0.0 copied to clipboard

Isolate-aware Flutter logs, bounded history, safe HTTP logging and Sentry incident capture.

example/observatory_example.dart

import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:observatory/observatory.dart';

Future<void> main() async {
  return Observatory.run<void>(
    thread: ObservatoryThread.foreground,
    zoneName: 'main',
    config: Config(
      filter: ObservationFilter(
        enabled: true,
        excludedLogs: const [
          'Heartbeat tick',
        ],
        excludedHttpUrls: [
          RegExp(r'/health$'),
        ],
        excludedBlocTypes: const [
          'HydratedBloc',
        ],
      ),
      httpLog: const HttpLogSpec.detailed(),
      sentry: SentrySpec(
        enabled: const String.fromEnvironment('SENTRY_DSN').isNotEmpty,
        appPackageName: 'observatory_example',
        dsn: const String.fromEnvironment('SENTRY_DSN'),
        environment: kReleaseMode ? 'production' : 'development',
        release: 'observatory_example@0.1.0+1',
        dist: '1',
        sampleRate: 1,
        attachScreenshot: true,
        attachLogs: true,
        logsMaxBreadcrumbs: 50,
        logsLevel: LogLevel.warning,
        maxBreadcrumbs: 100,
        dedupeTtl: const Duration(minutes: 2),
        dedupeMaxEntries: 200,
        anrEnabled: true,
        anrTimeoutInterval: const Duration(seconds: 5),
        enableAppHangTracking: true,
        appHangTimeoutInterval: const Duration(seconds: 2),
      ),
    ),
    body: () async {
      await Observatory.bindUser(id: 'user-42', email: 'qa@example.com');
      await Observatory.bindDevice(
        connectedDeviceId: 'device-7',
        platformDeviceId: 'pixel-8',
      );

      final dio = Dio(
        BaseOptions(baseUrl: 'https://api.example.com'),
      );
      Observatory.attachTo(dio);

      runApp(ExampleApp(dio: dio));
    },
  );
}

class ExampleApp extends StatelessWidget {
  final Dio dio;

  const ExampleApp({
    required this.dio,
    super.key,
  });

  @override
  Widget build(BuildContext context) {
    return ObservatoryWidget(
      child: MaterialApp(
        navigatorObservers: Observatory.navigatorObservers,
        home: ExampleHome(
          dio: dio,
        ),
      ),
    );
  }
}

class ExampleHome extends StatelessWidget {
  final Dio dio;

  const ExampleHome({
    required this.dio,
    super.key,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Observatory example'),
        actions: [
          IconButton(
            onPressed: () {
              Navigator.of(context).push(
                MaterialPageRoute<void>(
                  builder: (context) => const ObservatoryLogScreen(
                    appBarTitle: 'Logs',
                  ),
                ),
              );
            },
            icon: const Icon(Icons.bug_report_outlined),
          ),
        ],
      ),
      body: ListView(
        padding: const EdgeInsets.all(16),
        children: [
          FilledButton(
            onPressed: () {
              Observatory.record(LogLevel.info, 'Home opened');
            },
            child: const Text('Record info'),
          ),
          const SizedBox(height: 8),
          FilledButton(
            onPressed: _syncProfile,
            child: const Text('Catch and capture'),
          ),
          const SizedBox(height: 8),
          FilledButton(
            onPressed: _pingBackend,
            child: const Text('HTTP with capture'),
          ),
        ],
      ),
    );
  }

  Future<void> _syncProfile() async {
    try {
      throw const FormatException('invalid profile payload');
    } on Object catch (error, stackTrace) {
      await Observatory.capture(
        LogLevel.error,
        'Profile sync failed',
        error: error,
        stackTrace: stackTrace,
      );
    }
  }

  Future<void> _pingBackend() async {
    try {
      await dio.get<void>('/v1/profile');
    } on Object catch (error, stackTrace) {
      await Observatory.capture(
        LogLevel.error,
        'Profile request failed',
        error: error,
        stackTrace: stackTrace,
      );
    }
  }
}
1
likes
130
points
249
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Isolate-aware Flutter logs, bounded history, safe HTTP logging and Sentry incident capture.

Repository (GitHub)
View/report issues

Topics

#observability #logging #diagnostics #isolates #monitoring

License

MIT (license)

Dependencies

dio, domain_error, flutter, flutter_bloc, sentry_dio, sentry_flutter, talker, talker_bloc_logger, talker_flutter

More

Packages that depend on observatory