any_logger 1.0.4 copy "any_logger: ^1.0.4" 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_provider and configure it (see User Tracking section)
  • Use MemoryIdProvider for non-persistent IDs
  • Remove %did from 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 %did or %sid, the ID provider never runs
  • Use MemoryIdProvider if persistence isn't needed
  • Enable batching for network appenders (extension packages)
  • Only import extension packages you actually use

🏆 Best Practices #

  1. Start simple - Use basic console logging, add features as needed
  2. Use self-debugging when troubleshooting logger configuration
  3. Set appropriate log levels - DEBUG for development, INFO/WARN for production
  4. Use named loggers via the mixin for better organization
  5. Add tracking IDs (%did/%sid) only when you need user journey tracking
  6. Use MDC for request/transaction tracking
  7. Configure rotation for file appenders to manage disk space
  8. 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 #

👏 Funding #


Happy Logging! 🎉

0
likes
0
points
1.12k
downloads

Publisher

verified publisherraoulsson.com

Weekly Downloads

A powerful, flexible, and intuitive logging library for Dart and Flutter with progressive complexity - from one-line setup to enterprise configurations.

Repository (GitHub)
View/report issues

Topics

#logging

Documentation

Documentation

Funding

Consider supporting this project:

github.com
www.buymeacoffee.com

License

unknown (license)

More

Packages that depend on any_logger