any_logger 1.0.4  any_logger: ^1.0.4 copied to clipboard
any_logger: ^1.0.4 copied to clipboard
A powerful, flexible, and intuitive logging library for Dart and Flutter with progressive complexity - from one-line setup to enterprise configurations.
Any Logger #
A powerful, flexible, and intuitive logging library for Dart and Flutter applications with automatic device/session tracking and progressive complexity - from one-line setup to enterprise-grade configurations.
✨ Why Any Logger? #
- 🚀 Zero Configuration - Start logging with literally one line of code
- 📱 Flutter-First - Built for mobile apps with proper app directory support
- 🔍 Automatic User Tracking - Built-in anonymous device/session/version identification
- 📈 Progressive Complexity - Simple for beginners, powerful for experts
- ⚡ Performance First - Optimized with early exits, caching, and lazy evaluation
- 🎯 Production Ready - Battle-tested with file rotation, batching, and error handling
- 🚨 Fail-Fast Design - Clear errors instead of silent failures
- 📦 Minimal Dependencies - Core library has only one dependency (crypto)
📦 Installation #
dependencies:
  any_logger: ^1.0.1
That's it! No other dependencies needed to start logging.
🚀 Quick Start #
Flutter Apps #
import 'package:any_logger/any_logger.dart';
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  await LoggerFactory.initConsole();
  
  Logger.info("Flutter app started!");
  runApp(MyApp());
}
Dart Console Apps #
import 'package:any_logger/any_logger.dart';
void main() {
  Logger.info("I'm logging!");  // That's it! Auto-configures everything
}
No initialization needed for simple cases. The logger auto-configures on first use.
One Line with Options #
// Dart or Flutter
void main() {
  LoggerFactory.initSimpleConsole(level: Level.DEBUG);
  
  Logger.debug("Debug mode enabled");
  Logger.info("Application started");
  Logger.error("An error occurred");
}
📖 Configuration Examples #
Basic Console Logging #
// Simple console with custom format
LoggerFactory.initConsole(
  format: '🚀 %l: %m',
  level: Level.DEBUG,
);
// Professional console with file location
LoggerFactory.initProConsole(
  level: Level.DEBUG,
);
// Output: [10:30:45][ROOT_LOGGER][INFO][main:42] User logged in [lib/main.dart(42:5)]
File Logging #
// Simple file logging
await LoggerFactory.initFile(
  filePattern: 'myapp',
  fileLevel: Level.DEBUG,
  consoleLevel: Level.INFO,  // Optional console output
);
// Creates: myapp_2025-01-20.log
// Professional file setup
await LoggerFactory.initProFile(
  filePattern: 'myapp',
  fileLevel: Level.DEBUG,
  consoleLevel: Level.INFO,
);
Using Presets #
// Development - verbose with full stack traces
await LoggerFactory.initWithPreset(LoggerPresets.development);
// Production - optimized with essential info only
await LoggerFactory.initWithPreset(LoggerPresets.production);
Builder Pattern #
// Console and file logging
await LoggerFactory.builder()
    .console(level: Level.INFO)
    .file(
      filePattern: 'app',
      level: Level.DEBUG,
      path: 'logs/',
    )
    .build();
Using the AnyLogger Mixin #
class PaymentService with AnyLogger {
  @override
  String get loggerName => 'PaymentService';
  
  void processPayment(String userId, double amount) {
    logInfo('Processing payment for $userId: \$$amount');
    
    if (isDebugEnabled) {
      logDebug('Payment details: ${_getExpensiveDetails()}');
    }
    
    logInfo('Payment successful');
  }
}
📝 Format Patterns #
| Pattern | Description | Example Output | 
|---|---|---|
| %d | Date/time | 2025-01-20 10:30:45 | 
| %l | Log level | INFO | 
| %m | Message | User logged in | 
| %c | Class.method:line | UserService.login:42 | 
| %f | File location | lib/user.dart(42:5) | 
| %i | Logger name | UserService | 
| %t | Tag | AUTH | 
Example Formats #
// Minimal
'%l: %m'
// Output: INFO: User logged in
// With timestamp
'%d [%l] %m'
// Output: 10:30:45 [INFO] User logged in
// With location
'[%l][%c] %m'
// Output: [INFO][UserService.login:42] User logged in
// More complete
'[%d][%did][%sid][%i][%l][%c] %m [%f]'
// Output: [11:50:43.399][lw8aqkjl][2xny54b4][ROOT_LOGGER][INFO][ServiceFactory.initializeCoreServices:326] Core services initialized successfully [package:my_app/service/service_factory.dart(326:7)]
🔍 Automatic User Tracking #
Any Logger can automatically generate and persist anonymous IDs to help you understand user behavior without compromising privacy:
- Device ID (%did) - Persists across app restarts, unique per device
- Session ID (%sid) - New for each app launch, tracks individual sessions
- App Version (%app) - Your application version for tracking deployments
Basic Usage (Dart Console/Server) #
// Just add IDs to your format - works automatically on Dart console/server
LoggerFactory.initConsole(
  format: '[%did][%sid] %l: %m',
);
// Output: [a3f5c8d2][e7b9f1a4] INFO: User clicked button
Flutter Setup for Device/Session IDs #
Flutter apps need additional setup for persistent device IDs:
# Add to pubspec.yaml
dependencies:
  any_logger: ^1.0.1
  path_provider: ^2.1.5  # Required for %did on Flutter
import 'package:path_provider/path_provider.dart';
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  // Connect path_provider to AnyLogger (one line!)
  LoggerFactory.setGetAppDocumentsDirectoryFnc(getApplicationDocumentsDirectory);
  
  await LoggerFactory.initConsole(
    format: '[%app][%did][%sid] %l: %m',
  );
  
  LoggerFactory.setAppVersion('1.2.3');
  
  Logger.info('Device ID persists across app restarts!');
  // Output: [1.2.3][a3f5c8d2][e7b9f1a4] INFO: Device ID persists...
  
  runApp(MyApp());
}
Alternative: Memory-Only IDs (No path_provider needed) #
void main() async {
  // Use MemoryIdProvider when persistence isn't needed
  LoggerFactory.setIdProvider(MemoryIdProvider());
  
  await LoggerFactory.initConsole(
    format: '[%did][%sid] %l: %m',  // IDs work but don't persist
  );
  
  runApp(MyApp());
}
This tracking helps you:
- Debug user-reported issues by asking for their logs
- Track which app versions have specific issues
- Understand user journeys without collecting personal data
- Maintain GDPR compliance with anonymous identifiers
🏷️ MDC - Mapped Diagnostic Context #
Track context across all your logs - perfect for request tracking, user sessions, or feature flags:
// Set global context
LoggerFactory.setMdcValue('userId', 'user-123');
LoggerFactory.setMdcValue('feature', 'new-checkout');
// Use in format with %X{key}
LoggerFactory.initConsole(
  format: '[%X{userId}][%X{feature}] %l: %m',
);
// All logs now include context
Logger.info('Checkout started');  
// Output: [user-123][new-checkout] INFO: Checkout started
// Clean up when done
LoggerFactory.removeMdcValue('userId');
Request Tracking Example #
class ApiServer {
  void handleRequest(Request request) {
    final requestId = Uuid().v4();
    
    // Set request context
    LoggerFactory.setMdcValue('requestId', requestId);
    LoggerFactory.setMdcValue('endpoint', request.uri.path);
    
    Logger.info('Request started');
    // Process request...
    Logger.info('Request completed');
    
    // Clean up
    LoggerFactory.clearMdc();
  }
}
🧩 Extension Packages #
The core any_logger library is intentionally kept lightweight. Additional appenders are available through optional extension packages:
Available Extensions #
| Package | Description | When to Use | 
|---|---|---|
| any_logger_json_http | JSON over HTTP logging | When sending logs to REST APIs, Logstash, etc. | 
| any_logger_email | Email notifications | For critical alerts and error notifications | 
| any_logger_mysql | MySQL database logging | For structured, queryable log storage | 
Installation #
dependencies:
  any_logger: ^1.0.1
  any_logger_json_http: ^1.0.0  # Only if needed
  any_logger_email: ^1.0.0      # Only if needed
Usage Example #
import 'package:any_logger/any_logger.dart';
import 'package:any_logger_json_http/any_logger_json_http.dart';
await LoggerFactory.builder()
    .console()  // Core package
    .file()     // Core package
    .jsonHttp(  // Extension package
      url: 'https://api.example.com/logs',
      level: Level.ERROR,
      bufferSize: 100,
    )
    .build();
⚡ Performance Optimization #
Early Exit Pattern #
// ❌ Bad - always computes expensive operation
logger.logDebug(expensiveComputation());
// ✅ Good - only computes if debug is enabled
if (logger.isDebugEnabled) {
  logger.logDebug(expensiveComputation());
}
// ✅ Better - use supplier for lazy evaluation
logger.logDebugSupplier(() => expensiveComputation());
🔍 Troubleshooting #
Enable Self-Debugging #
Having issues? Enable self-debugging to see what the logger is doing:
// See internal logger operations
LoggerFactory.builder()
    .console(level: Level.INFO)
    .withSelfDebug(Level.DEBUG)  // Shows platform detection, ID provider selection, etc.
    .build();
// Output:
// [LoggerFactory.DEBUG] Platform: Dart | IDs: %did+%sid | Provider: FileIdProvider
// [LoggerFactory.DEBUG] Self-debugging enabled
// [LoggerFactory.DEBUG] Logger initialized with 1 appender
Common Flutter Issues #
"path_provider Not Configured for Device ID (%did)"
The logger will show a clear error message with instructions. Either:
- Add path_providerand configure it (see User Tracking section)
- Use MemoryIdProviderfor non-persistent IDs
- Remove %didfrom your format
"No appender registered for type 'JSON_HTTP'"
Add and import the required extension package:
dependencies:
  any_logger_json_http: ^1.0.1
"Permission denied" on Mobile
Use MemoryIdProvider instead of file-based storage:
LoggerFactory.setIdProvider(MemoryIdProvider());
Performance Tips #
- If you don't use %didor%sid, the ID provider never runs
- Use MemoryIdProviderif persistence isn't needed
- Enable batching for network appenders (extension packages)
- Only import extension packages you actually use
🏆 Best Practices #
- Start simple - Use basic console logging, add features as needed
- Use self-debugging when troubleshooting logger configuration
- Set appropriate log levels - DEBUG for development, INFO/WARN for production
- Use named loggers via the mixin for better organization
- Add tracking IDs (%did/%sid) only when you need user journey tracking
- Use MDC for request/transaction tracking
- Configure rotation for file appenders to manage disk space
- Flush logs before app termination: await LoggerFactory.flushAll()
📄 License #
MIT License - see LICENSE file for details.
🙏 Acknowledgments #
This library is a fork of Log4Dart2 by Ephenodrom, enhanced with modern features, performance optimizations, automatic ID tracking, and a simplified API.
📮 Support #
- 📧 Email: hello@raoulsson.com
- 🐛 Issues: GitHub Issues
- 💬 Discussions: GitHub Discussions
👏 Funding #
Happy Logging! 🎉