import 'package:flutter/foundation.dart'; import 'package:logger/logger.dart'; /// AppLogger is a singleton class that provides centralized logging functionality /// throughout the application using the logger package. class AppLogger { // Private constructor AppLogger._internal(); // Singleton instance static final AppLogger _instance = AppLogger._internal(); // Factory constructor to return the singleton instance factory AppLogger() => _instance; // Logger instance late final Logger _logger; // Initialize the logger with custom configuration void init({Level? logLevel, bool? stackTraceEnabled}) { _logger = Logger( level: logLevel ?? (kDebugMode ? Level.debug : Level.info), printer: PrettyPrinter( methodCount: stackTraceEnabled ?? false ? 2 : 0, errorMethodCount: 8, lineLength: 120, colors: true, printEmojis: true, dateTimeFormat: DateTimeFormat.onlyTimeAndSinceStart, ), output: _CustomConsoleOutput(), filter: _CustomLogFilter(), ); } // Get the logger instance (for advanced usage) Logger get logger => _logger; // Convenient logging methods void debug(message, {error, StackTrace? stackTrace}) { _logger.d(message, error: error, stackTrace: stackTrace); } void info(message, {error, StackTrace? stackTrace}) { _logger.i(message, error: error, stackTrace: stackTrace); } void warning(message, {error, StackTrace? stackTrace}) { _logger.w(message, error: error, stackTrace: stackTrace); } void error(message, {error, StackTrace? stackTrace}) { _logger.e(message, error: error, stackTrace: stackTrace); } void fatal(message, {error, StackTrace? stackTrace}) { _logger.f(message, error: error, stackTrace: stackTrace); } // Network logging void logNetwork({ required String method, required String url, int? statusCode, requestBody, responseBody, error, }) { final buffer = StringBuffer(); buffer.writeln('🌐 Network Request:'); buffer.writeln(' Method: $method'); buffer.writeln(' URL: $url'); if (statusCode != null) { buffer.writeln(' Status: $statusCode'); } if (requestBody != null) { buffer.writeln(' Request Body: $requestBody'); } if (responseBody != null) { buffer.writeln(' Response: $responseBody'); } if (error != null) { buffer.writeln(' Error: $error'); } if (error != null) { _logger.e(buffer.toString()); } else if (statusCode != null && statusCode >= 400) { _logger.w(buffer.toString()); } else { _logger.i(buffer.toString()); } } // Performance logging void logPerformance(String operation, Duration duration) { final milliseconds = duration.inMilliseconds; final message = '⏱️ Performance: $operation took ${milliseconds}ms'; if (milliseconds > 1000) { _logger.w(message); } else { _logger.d(message); } } // Navigation logging void logNavigation(String from, String to) { _logger.i('🧭 Navigation: $from → $to'); } // Custom log with tag void logWithTag(String tag, message, {Level? level}) { final taggedMessage = '[$tag] $message'; switch (level ?? Level.info) { case Level.debug: debug(taggedMessage); break; case Level.info: info(taggedMessage); break; case Level.warning: warning(taggedMessage); break; case Level.error: error(taggedMessage); break; case Level.fatal: fatal(taggedMessage); break; default: info(taggedMessage); } } // Close the logger (call this in app disposal if needed) void close() { _logger.close(); } } /// Custom log filter to control which logs are shown class _CustomLogFilter extends LogFilter { @override bool shouldLog(LogEvent event) { // In debug mode, show all logs if (kDebugMode) { return true; } // In release mode, only show warnings and above return event.level.value >= Level.warning.value; } } /// Custom console output for better control over log output class _CustomConsoleOutput extends ConsoleOutput { @override void output(OutputEvent event) { // You can customize how logs are output here // For example, you could write to a file in addition to console super.output(event); // Example: Write errors to a file (uncomment if needed) // if (event.level == Level.error || event.level == Level.fatal) { // _writeToFile(event.lines.join('\n')); // } } // Example method for writing to file (implement if needed) // Future _writeToFile(String log) async { // // Implementation for file writing // } } // Global logger instance for easy access final appLogger = AppLogger(); // Extension for convenient logging on any object extension LoggerExtension on Object { void logDebug([String? message]) { appLogger.debug(message ?? toString()); } void logInfo([String? message]) { appLogger.info(message ?? toString()); } void logWarning([String? message]) { appLogger.warning(message ?? toString()); } void logError([String? message, error, StackTrace? stackTrace]) { appLogger.error( message ?? toString(), error: error, stackTrace: stackTrace, ); } }