When a Flutter app misbehaves in production you have limited options. Crash reporting tools capture unhandled exceptions, but they miss the flow leading up to the crash — the API call that returned an unexpected payload, the auth state that went wrong, the navigation sequence that never completed.
The bunnylogs_flutter package gives every Flutter app a live log stream: a URL you can open on any device and watch log lines appear in real time as the app runs, from any platform, with no backend to set up.
flutter pub add bunnylogs_flutter
Or add it manually to pubspec.yaml:
dependencies:
bunnylogs_flutter: ^0.1.0
Create a log stream at bunnylogs.com and copy the UUID. Then:
import 'package:bunnylogs_flutter/bunnylogs_flutter.dart';
final logger = BunnyLogger(uuid: 'your-uuid-here');
logger.info('User signed in: $userId');
logger.warning('Cache miss — fetching from network');
logger.error('Payment failed: $error');
Open bunnylogs.com/live/your-uuid in a browser and you'll see each call appear as a timestamped, colour-coded log line.
If you already use the popular logger package, use BunnyLogsOutput as a LogOutput alongside ConsoleOutput to keep terminal output while also shipping to BunnyLogs:
import 'package:flutter/foundation.dart';
import 'package:logger/logger.dart';
import 'package:bunnylogs_flutter/bunnylogs_flutter.dart';
final log = Logger(
filter: kDebugMode ? DevelopmentFilter() : ProductionFilter(),
output: MultiOutput([
ConsoleOutput(),
BunnyLogsOutput(uuid: 'your-uuid-here'),
]),
printer: SimplePrinter(printTime: false),
);
log.i('Server connected');
log.w('Slow network response: ${ms}ms');
log.e('Checkout error', error: e, stackTrace: s);
ProductionFilter suppresses trace and debug messages in release builds, so you won't ship noisy debug output to production.
Create separate logger instances per feature area so the program field in each log entry identifies the source:
final networkLog = BunnyLogger(uuid: 'your-uuid', program: 'flutter/network');
final authLog = BunnyLogger(uuid: 'your-uuid', program: 'flutter/auth');
final cartLog = BunnyLogger(uuid: 'your-uuid', program: 'flutter/cart');
The live view lets you filter by program, so you can watch only the auth subsystem during a login debugging session.
In production you probably want to ship warnings and errors but not verbose debug output:
final logger = BunnyLogger(
uuid: 'your-uuid',
minLevel: BunnyLevel.warning,
enabled: !kDebugMode,
);
Store the UUID in a --dart-define build variable rather than hardcoding it:
# Build command
flutter build apk --dart-define=BUNNY_UUID=your-uuid
# Access in code
const uuid = String.fromEnvironment('BUNNY_UUID');
final logger = BunnyLogger(uuid: uuid, enabled: uuid.isNotEmpty);
All HTTP calls are fire-and-forget — they never block the UI thread. The http package works on Android, iOS, macOS, Linux, Windows, and web with no extra configuration. For Flutter Web, BunnyLogs serves a permissive CORS policy on /live/<uuid> so browser POSTs work out of the box.
May 1, 2025
April 15, 2025
April 8, 2025