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

Structured Flutter logging with redaction, rotating files, diagnostics, custom sinks, an in-app viewer, and a DevTools extension.

codecov GitHub Buy Me A Coffee PayPal Sponsor Support Me on Ko-fi

my_log #

Structured Flutter logging with colored console output, rotating files, automatic secret redaction, an in-app log viewer, diagnostics ZIP export, custom sinks, global error capture, and a Flutter DevTools extension.

Requires Dart 3.9+ and Flutter 3.35+. Version 2.0.0 is verified with Flutter 3.47.1 and Dart 3.13.1.

Features #

  • Trace, debug, info, warning, error, and fatal levels.
  • Structured fields, tags, flags, errors, stack traces, timestamps, and session IDs.
  • Separate minimum levels for the pipeline, console, and file destinations.
  • JSON Lines, readable text, and backward-compatible legacy text files.
  • Size-based file rotation, retention cleanup, bounded file count, and periodic flush.
  • Recursive redaction before an entry reaches history, console, files, sinks, diagnostics, or DevTools.
  • Bounded in-memory history plus live entry, clear, and sink-error streams.
  • Extensible async sinks for APIs, crash reporters, databases, or test capture.
  • Optional capture of Flutter framework and root-isolate errors.
  • Searchable in-app overlay with level, tag, and flag filters, counters, pause, copy, clear, export, and bounded memory.
  • A debug-only Flutter DevTools tab for live logs, filtering, counts, copy, and clear.
  • Redacted diagnostics ZIPs containing structured logs, metadata, attachments, and current/rotated log files.
  • Console and in-app logging on web. Native file writes are intentionally disabled on web.

Installation #

dependencies:
  my_log: ^2.0.0
flutter pub get

Quick start #

Resolve a writable file path with path_provider on native platforms, then configure the shared logger before runApp:

import 'package:flutter/widgets.dart';
import 'package:my_log/my_log.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await myLog.configure(
    MyLogConfig(
      filePath: nativeLogPath, // Omit on web.
      fileFormat: MyLogFileFormat.jsonLines,
      minimumLevel: Level.trace,
      consoleMinimumLevel: Level.debug,
      fileMinimumLevel: Level.info,
      maxFileSizeBytes: 5 * 1024 * 1024,
      maxFiles: 5,
      retention: const Duration(days: 7),
      captureFlutterErrors: true,
      diagnosticMetadata: const <String, Object?>{
        'app': 'Example',
        'environment': 'production',
      },
    ),
  );

  runApp(const App());
}

For console-only logging, including Flutter web:

await myLog.configure(
  const MyLogConfig(
    consoleEnabled: true,
    captureFlutterErrors: true,
  ),
);

Passing filePath on web throws UnsupportedError rather than silently losing logs.

Write structured logs #

The original methods remain available:

myLog.trace('Loading checkout');
myLog.debug('Button pressed');
myLog.info('Payment created', tag: 'payment', flag: 'checkout');
myLog.warning('Slow response');
myLog.error('Request failed', tag: 'network');
myLog.fatal('Database unavailable', error: error, stackTrace: stackTrace);

Use the *Entry methods when you need structured fields or an explicit stack trace:

myLog.errorEntry(
  'Checkout request failed',
  tag: 'network',
  flag: 'checkout',
  error: error,
  stackTrace: stackTrace,
  fields: <String, Object?>{
    'orderId': 'ORDER-42',
    'attempt': 2,
    'latencyMs': 840,
  },
);

For dynamic levels, call myLog.log(Level.info, ...).

Secret redaction #

MyLogRedactor recursively masks common credential and personal-data keys such as authorization, cookie, email, password, phone, secret, token, access_token, refresh_token, and api_key. Bearer credentials and key-value secrets in text are also masked.

Redaction happens before an entry is retained or dispatched, so every destination receives the safe value:

await myLog.configure(
  MyLogConfig(
    redactor: MyLogRedactor(
      sensitiveKeys: <String>{
        ...MyLogRedactor.defaultSensitiveKeys,
        'customer_id',
      },
      callback: (value) => value is String
          ? value.replaceAll(RegExp(r'TENANT-\d+'), '[tenant]')
          : value,
    ),
  ),
);

Redaction reduces accidental exposure; always review diagnostics before sharing them.

Levels and tag filters #

await myLog.configure(
  const MyLogConfig(
    minimumLevel: Level.debug,
    consoleMinimumLevel: Level.warning,
    fileMinimumLevel: Level.info,
    includedTags: <String>{'payment', 'network'},
    excludedTags: <String>{'noisy-heartbeat'},
  ),
);

The pipeline minimum and tag filters run before history or any destination. includedTags is an allowlist; excludedTags always wins.

Rotating files #

Modern configuration writes one JSON object per line by default. Rotation occurs before the active file exceeds maxFileSizeBytes; older files use .1, .2, and so on. maxFiles includes the active file, and expired rotated files are removed during initialization.

await myLog.configure(
  MyLogConfig(
    filePath: nativeLogPath,
    fileFormat: MyLogFileFormat.jsonLines,
    maxFileSizeBytes: 2 * 1024 * 1024,
    maxFiles: 4,
    retention: const Duration(days: 3),
    flushInterval: const Duration(seconds: 2),
  ),
);

Call await myLog.flush() before a critical handoff and await myLog.close() when the logger is no longer needed.

In-app log overlay #

final consoleLogController = MyConsoleLogController();

MaterialApp(
  builder: (context, child) => MyConsoleLog(
    controller: consoleLogController,
    log: myLog,
    maxEntries: 1000,
    onExport: (_) async {
      final bundle = await myLog.exportDiagnostics();
      await bundle.save(); // Native platforms; use bundle.bytes on web.
    },
    children: <Widget>[child ?? const SizedBox.shrink()],
  ),
);

Show or hide it from anywhere that owns the controller:

consoleLogController.setShowConsoleLog(true);

When log is supplied, the overlay consumes structured entries and enables tag/flag filters. Omitting log keeps the legacy global package:logger output-listener behavior.

Flutter DevTools extension #

enableDevToolsExtension defaults to true. In a debug session:

  1. Run the application and open Flutter DevTools.
  2. Select the my_log extension tab.
  3. Filter live entries by search text, minimum level, tag, or flag.
  4. Pause polling, copy visible entries, or clear the application history.

The service extension is registered only in debug mode. Disable it when it is not wanted:

await myLog.configure(
  const MyLogConfig(enableDevToolsExtension: false),
);

Diagnostics ZIP export #

import 'dart:convert';

final bundle = await myLog.exportDiagnostics(
  metadata: <String, Object?>{
    'userFlow': 'checkout',
    'build': 1042,
  },
  attachments: <MyLogAttachment>[
    MyLogAttachment(
      name: 'state/cart.json',
      bytes: utf8.encode(redactedCartJson),
    ),
  ],
);

final savedPath = await bundle.save(); // Native only.

The ZIP contains diagnostics.json, logs/session.jsonl, a safety README, supplied attachments, and any files exposed by the rotating file sink. On web, pass bundle.bytes to your download implementation.

Custom and remote sinks #

Use CallbackMyLogSink for a small integration:

final remoteSink = CallbackMyLogSink(
  onWrite: (entry) => api.send(entry.toJson()),
  onFlush: api.flush,
  onClose: api.close,
);

await myLog.configure(
  MyLogConfig(sinks: <MyLogSink>[remoteSink]),
);

For reusable integrations, implement MyLogSink. Writes are serialized in call order. Sink failures do not throw from logging calls; observe them through myLog.sinkErrors:

final subscription = myLog.sinkErrors.listen(reportSinkFailure);

MemoryMyLogSink is available for tests and diagnostic utilities.

Global Flutter errors #

Set captureFlutterErrors: true to install handlers for FlutterError.onError and PlatformDispatcher.instance.onError. Existing handlers are called by default. close() restores the handlers only when this logger still owns them.

await myLog.configure(
  const MyLogConfig(
    captureFlutterErrors: true,
    preserveExistingErrorHandlers: true,
  ),
);

Errors from additional isolates still need to be forwarded by the application.

History and streams #

final snapshot = myLog.entries;
final entrySubscription = myLog.entryStream.listen(handleEntry);
final clearSubscription = myLog.clearStream.listen((_) => handleClear());

myLog.clearHistory();

History is bounded by maxHistoryEntries and exposed as an immutable snapshot.

Upgrade from 1.0.x #

The legacy setup API remains supported and keeps legacy text-file formatting:

await myLog.setUp(
  path: nativeLogPath,
  printTime: true,
  isLogging: true,
  noteInfoFileLog: 'Application log',
);

Existing trace, debug, info, warning, error, and fatal calls continue to work. Move to configure(MyLogConfig(...)) when you want structured JSON Lines, rotation, retention, filters, redaction customization, error capture, diagnostics, or custom sinks.

Platform support #

Capability Android/iOS macOS/Linux/Windows Web
Console and structured history Yes Yes Yes
In-app overlay Yes Yes Yes
DevTools extension in debug Yes Yes Yes
Rotating native files Yes Yes No
Diagnostics bundle bytes Yes Yes Yes
MyLogDiagnosticsBundle.save() Yes Yes No

Development checks #

make check
make devtools-check
flutter pub publish --dry-run

More background documentation is available at https://wong-coupon.gitbook.io/flutter/easy-code/log-color.

Maintainers #

Questions and contributions are welcome. Contact ThaoDoan or DucNguyen.

4
likes
150
points
86
downloads
screenshot

Documentation

API reference

Publisher

verified publisherwongcoupon.com

Weekly Downloads

Structured Flutter logging with redaction, rotating files, diagnostics, custom sinks, an in-app viewer, and a DevTools extension.

Repository (GitHub)
View/report issues

Topics

#logging #color #save-file #popup-realtime-log #structured-logging

Funding

Consider supporting this project:

buymeacoffee.com
ko-fi.com

License

MIT (license)

Dependencies

archive, flutter, flutter_staggered_animations, gap, logger

More

Packages that depend on my_log