simple_logger Logging Guide
simple_logger provides a straightforward, developer-friendly logging API built on top of the standard logging package. It features caller file/line capture (with IDE clickable links), lazy log evaluation, customizable prefixes/emojis, and flexible output formatters.
Guidelines
- Instantiation:
SimpleLogger()is implemented as a singleton factory. CallingSimpleLogger()returns the shared global logger instance.
- Level Configuration:
- Configure the logging level early in application bootstrap (e.g., in
main()beforerunApp()). - Use
logger.setLevel(...)to set the active threshold (Level.INFO,Level.WARNING,Level.SEVERE, etc.).
- Configure the logging level early in application bootstrap (e.g., in
- Caller Info Performance:
includeCallerInfo: truecaptures caller stack frame locations, making logs clickable in IDEs. Because stack trace parsing is CPU-intensive, only enableincludeCallerInfoin debug mode (kDebugModeor!kReleaseMode).
- Lazy Evaluation:
- Pass a closure
() => 'message'instead of evaluating heavy string interpolation eagerly if the log level might be suppressed.
- Pass a closure
- Log Routing & Listeners:
- Use
logger.onLoggedor customlogger.formatterto forward logs to external error reporting services (e.g. Sentry, Crashlytics) in production.
- Use
Examples
1. Basic Bootstrap and Configuration
import 'package:flutter/foundation.dart';
import 'package:simple_logger/simple_logger.dart';
void configureLogger() {
final logger = SimpleLogger();
logger.setLevel(
kReleaseMode ? Level.WARNING : Level.FINEST,
includeCallerInfo: kDebugMode,
);
// Optional: Custom emoji prefixes
logger.levelPrefixes = {
Level.INFO: '💡 INFO',
Level.WARNING: '⚠️ WARNING',
Level.SEVERE: '🚨 SEVERE',
};
}
2. Logging Messages and Lazy Evaluation
import 'package:simple_logger/simple_logger.dart';
final logger = SimpleLogger();
void processPayment(String orderId, Map<String, dynamic> rawPayload) {
// Simple message
logger.info('Starting payment for order: $orderId');
// Lazy evaluation (expensive serialization only executed if FINEST is enabled)
logger.finest(() => 'Order payload: ${rawPayload.toString()}');
try {
// Business logic
} catch (e, stackTrace) {
logger.severe('Payment failed for $orderId', e, stackTrace);
}
}
3. Custom Formatter for Production / CI
import 'package:simple_logger/simple_logger.dart';
void setupCiFormatter() {
final logger = SimpleLogger();
logger.formatter = (info) {
final caller = info.callerInfo.isNotEmpty ? ' [${info.callerInfo}]' : '';
return '[${info.time.toIso8601String()}] [${info.level.name}]$caller: ${info.message}';
};
}
Common Pitfalls & Anti-Patterns
- ❌ Anti-pattern: Enabling
includeCallerInfo: trueunconditionally in release builds, causing performance slowdowns.- ✔️ Correct: Guard caller info with
kDebugModeorassert(...).
- ✔️ Correct: Guard caller info with
- ❌ Anti-pattern: Using standard
print()across the codebase alongsideSimpleLogger().- ✔️ Correct: Route all application logs through
SimpleLogger()for consistent level filtering and formatting.
- ✔️ Correct: Route all application logs through