auto_logger 1.1.0 copy "auto_logger: ^1.1.0" to clipboard
auto_logger: ^1.1.0 copied to clipboard

Automatic debug logging for Flutter apps. Zero-setup capture of HTTP, platform channels, pointer events, keyboard, navigation, lifecycle, errors, and more.

auto_logger #

Debug logging for Flutter apps with automatic capture of HTTP, platform channels, pointer events, keyboard, navigation, lifecycle, errors, and more.

This package includes all core features plus Flutter-specific logging, so you only need this one package for Flutter apps.

Goal #

100% complete logging — every single thing that happens in your app should be logged so that when something goes wrong during development in the emulator/IDE, you can debug and fix it entirely by reading the logs without needing to reproduce the issue or add more logging.

Installation #

dependencies:
  auto_logger: ^1.0.0

Quick Start #

import 'package:auto_logger/auto_logger.dart';

void main() {
  AutoLogger.run(() => MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorObservers: [AutoLogger.navObserver],
      onUnknownRoute: AutoLogger.onUnknownRoute,
      home: HomeScreen(),
    );
  }
}

What's Logged Automatically #

Category Native Web
HTTP (dart:io) ✅ Auto ❌ (use Dio)
HTTP (Dio) ✅ Semi ✅ Semi
File operations ✅ Auto ❌ N/A
Socket connections ✅ Auto ❌ N/A
SharedPreferences ✅ Semi ✅ Semi
Hive storage ✅ Semi ✅ Semi
Drift SQL ✅ Semi ✅ Semi
WebSocket ✅ Semi ✅ Semi
gRPC ✅ Semi ✅ Semi
Timers ✅ Auto ✅ Auto
Errors/crashes ✅ Auto ✅ Auto
Print statements ✅ Auto ✅ Auto
Pointer events ✅ Auto ✅ Auto
Keyboard & focus ✅ Auto ✅ Auto
Navigation ✅ Semi ✅ Semi
Lifecycle & accessibility ✅ Auto ✅ Auto
Scroll & layout ✅ Auto ✅ Auto
Frame drops & jank ✅ Auto ✅ Auto
Memory allocations ✅ Auto ✅ Auto
Asset loading ✅ Auto ✅ Auto
Image cache ✅ Auto ✅ Auto
Platform channels ✅ Auto ✅ Auto

Auto = no setup needed, Semi = one-time wrapper/observer setup

Note: Default minLevel is WARN. Most automatic events are logged at DEBUG level and won't appear unless you set logger.minLevel = LogLevel.debug. Errors, crashes, timeouts, and stuck operations are always logged (WARN/ERROR/FATAL).

Web: Add Dio Interceptor for HTTP Logging #

IMPORTANT: On Flutter Web, HttpOverrides don't work. You MUST use Dio with our interceptor:

import 'package:dio/dio.dart';

final dio = Dio();

// Add this interceptor for HTTP logging on web
dio.interceptors.add(InterceptorsWrapper(
  onRequest: (options, handler) {
    loggingDioInterceptor.onRequest(options);
    handler.next(options);
  },
  onResponse: (response, handler) {
    loggingDioInterceptor.onResponse(response);
    handler.next(response);
  },
  onError: (error, handler) {
    loggingDioInterceptor.onError(error);
    handler.next(error);
  },
));

Log Format #

[TIME] [LEVEL] [SESSION] [CID] [COMPONENT] [EVENT] | MESSAGE | {METADATA}

Problem Markers #

  • ⚠️PROBLEM - Error with context
  • 🔴CRASH - Fatal crash
  • ⏰TIMEOUT - Operation timeout
  • 🔒LEAK - Memory leak detected
  • ❌STUCK - Operation stuck/hung
  • 🥶FREEZE - UI frozen/unresponsive

Deduplication #

Errors include:

  • fingerprint = hash of error type + location (same bug)
  • trailHash = hash of user actions before error (same flow)

Optional Integrations #

// BLoC - create observer extending BlocObserver
class LoggingBlocObserver extends BlocObserver {
  @override void onCreate(BlocBase b) { super.onCreate(b); blocLogging.onCreate(b); }
  @override void onEvent(Bloc b, Object? e) { super.onEvent(b, e); blocLogging.onEvent(b, e); }
  @override void onChange(BlocBase b, Change c) { super.onChange(b, c); blocLogging.onChange(b, c); }
  @override void onTransition(Bloc b, Transition t) { super.onTransition(b, t); blocLogging.onTransition(b, t); }
  @override void onError(BlocBase b, Object e, StackTrace s) { super.onError(b, e, s); blocLogging.onError(b, e, s); }
  @override void onClose(BlocBase b) { super.onClose(b); blocLogging.onClose(b); }
}
Bloc.observer = LoggingBlocObserver();

// Riverpod - create observer extending ProviderObserver
class LoggingProviderObserver extends ProviderObserver {
  @override void didAddProvider(...) => riverpodLogging.didAddProvider(...);
  // ... other overrides calling riverpodLogging methods
}
ProviderScope(observers: [LoggingProviderObserver()], child: ...)

// State snapshot on errors
AutoLogger.setStateSnapshotCallback(() => {'bloc': myBloc.state.toString()});

// Appwrite Realtime (monitor function executions from a long-running Dart app)
appwriteLogger.subscribe(realtime.subscribe(['executions']));

// WebSocket
final channel = LoggingWebSocketChannel.connect(Uri.parse('wss://example.com/ws'));

// Drift SQL (add .interceptWith to your database setup - logs ALL queries automatically)
NativeDatabase.createInBackground(file).interceptWith(loggingQueryInterceptor)

// gRPC (uses HTTP/2, not captured by HttpOverrides)
final result = await grpcLogger.call('UserService.GetUser', () => stub.getUser(request));

// SharedPreferences (works on web where dart:io file logging doesn't work)
final prefs = await SharedPreferences.getInstance();
final loggingPrefs = LoggingSharedPreferences(prefs);
await loggingPrefs.setString('key', 'value');
final value = loggingPrefs.getString('key');

// Hive (works on all platforms including web)
final box = await Hive.openBox('myBox');
final loggingBox = LoggingHiveBox(box, name: 'myBox');
await loggingBox.put('key', 'value');

Defensive Coding Utilities #

9 Exception Types #

throw NetworkException('msg', statusCode: 500, url: url);
throw ValidationException('msg', field: 'email', invalidValue: v);
throw NotFoundException('msg', resourceType: 'User', resourceId: id);
throw StateException('msg', expectedState: 'ready', actualState: 'loading');
throw AppTimeoutException('op', Duration(seconds: 10));
throw PermissionException('msg', permission: 'camera');
throw AuthenticationException('msg');
throw StorageException('msg', path: '/file');
throw ParseException('msg', input: json, expectedFormat: 'JSON');

9 Validation Utilities #

Validate.notNull(v, 'name');
Validate.notEmpty(s, 'name');
Validate.listNotEmpty(l, 'name');
Validate.positive(n, 'name');
Validate.nonNegative(n, 'name');
Validate.inRange(n, 'name', 0, 100);
Validate.percentage(n, 'name');
Validate.email(s, 'name');
Validate.isTrue(cond, 'msg', field: 'name');

Safe Disposal (Flutter) #

class _MyState extends State<MyWidget> with SafeDisposalMixin {
  void initState() {
    super.initState();
    trackTextController(TextEditingController());
    trackAnimationController(AnimationController(vsync: this));
    trackSubscription(stream.listen((d) => safeSetState(() => _d = d)));
    trackTimer(Timer.periodic(Duration(seconds: 1), (_) => refresh()));
  }
  // All auto-disposed on widget dispose!
  // Logs 🔒LEAK if Timer still active or StreamController not closed
}

Loading Monitor #

// Detects stuck operations (default 2min threshold)
final result = await loadingMonitor.track('fetchData', () => api.getData());

// Hard timeout
final result = await withTimeout('op', () => api.call(), timeout: Duration(seconds: 30));

Documentation #

  • doc_ai_guide.md - Concise code-only reference for AI assistants
  • auto_logger_developer_documentation.md - Full developer documentation with examples
  • doc3_human_log_parsing_guide.md - How to read and interpret logs

For Appwrite/Pure Dart #

Use the dart_auto_logger package instead if you don't need Flutter-specific features.

License #

MIT

1
likes
160
points
46
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Automatic debug logging for Flutter apps. Zero-setup capture of HTTP, platform channels, pointer events, keyboard, navigation, lifecycle, errors, and more.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

drift, flutter, leak_tracker, meta, stack_trace, talker, uuid, web_socket_channel

More

Packages that depend on auto_logger