Files
unionflow-server-impl-quarkus/unionflow-mobile-apps/lib/core/utils/logger.dart

302 lines
9.6 KiB
Dart

/// Logger centralisé pour l'application
library logger;
import 'package:flutter/foundation.dart';
import '../constants/app_constants.dart';
/// Niveaux de log
enum LogLevel {
debug,
info,
warning,
error,
fatal,
}
/// Logger centralisé pour toute l'application
class AppLogger {
// Empêcher l'instanciation
AppLogger._();
/// Couleurs ANSI pour les logs en console
static const String _reset = '\x1B[0m';
static const String _red = '\x1B[31m';
static const String _green = '\x1B[32m';
static const String _yellow = '\x1B[33m';
static const String _blue = '\x1B[34m';
static const String _magenta = '\x1B[35m';
static const String _cyan = '\x1B[36m';
static const String _white = '\x1B[37m';
/// Log de niveau DEBUG (bleu)
static void debug(String message, {String? tag}) {
if (AppConstants.enableLogging && kDebugMode) {
_log(LogLevel.debug, message, tag: tag, color: _blue);
}
}
/// Log de niveau INFO (vert)
static void info(String message, {String? tag}) {
if (AppConstants.enableLogging && kDebugMode) {
_log(LogLevel.info, message, tag: tag, color: _green);
}
}
/// Log de niveau WARNING (jaune)
static void warning(String message, {String? tag}) {
if (AppConstants.enableLogging && kDebugMode) {
_log(LogLevel.warning, message, tag: tag, color: _yellow);
}
}
/// Log de niveau ERROR (rouge)
static void error(
String message, {
String? tag,
dynamic error,
StackTrace? stackTrace,
}) {
if (AppConstants.enableLogging) {
_log(LogLevel.error, message, tag: tag, color: _red);
if (error != null) {
_log(LogLevel.error, 'Error: $error', tag: tag, color: _red);
}
if (stackTrace != null) {
_log(LogLevel.error, 'StackTrace:\n$stackTrace', tag: tag, color: _red);
}
// TODO: Envoyer à un service de monitoring (Sentry, Firebase Crashlytics)
if (AppConstants.enableCrashReporting) {
_sendToMonitoring(message, error, stackTrace);
}
}
}
/// Log de niveau FATAL (magenta)
static void fatal(
String message, {
String? tag,
dynamic error,
StackTrace? stackTrace,
}) {
if (AppConstants.enableLogging) {
_log(LogLevel.fatal, message, tag: tag, color: _magenta);
if (error != null) {
_log(LogLevel.fatal, 'Error: $error', tag: tag, color: _magenta);
}
if (stackTrace != null) {
_log(LogLevel.fatal, 'StackTrace:\n$stackTrace', tag: tag, color: _magenta);
}
// TODO: Envoyer à un service de monitoring (Sentry, Firebase Crashlytics)
if (AppConstants.enableCrashReporting) {
_sendToMonitoring(message, error, stackTrace, isFatal: true);
}
}
}
/// Log d'une requête HTTP
static void httpRequest({
required String method,
required String url,
Map<String, dynamic>? headers,
dynamic body,
}) {
if (AppConstants.enableLogging && kDebugMode) {
final buffer = StringBuffer();
buffer.writeln('┌─────────────────────────────────────────────────');
buffer.writeln('│ HTTP REQUEST');
buffer.writeln('├─────────────────────────────────────────────────');
buffer.writeln('│ Method: $method');
buffer.writeln('│ URL: $url');
if (headers != null && headers.isNotEmpty) {
buffer.writeln('│ Headers:');
headers.forEach((key, value) {
buffer.writeln('$key: $value');
});
}
if (body != null) {
buffer.writeln('│ Body: $body');
}
buffer.writeln('└─────────────────────────────────────────────────');
_log(LogLevel.debug, buffer.toString(), color: _cyan);
}
}
/// Log d'une réponse HTTP
static void httpResponse({
required int statusCode,
required String url,
Map<String, dynamic>? headers,
dynamic body,
Duration? duration,
}) {
if (AppConstants.enableLogging && kDebugMode) {
final buffer = StringBuffer();
buffer.writeln('┌─────────────────────────────────────────────────');
buffer.writeln('│ HTTP RESPONSE');
buffer.writeln('├─────────────────────────────────────────────────');
buffer.writeln('│ Status: $statusCode');
buffer.writeln('│ URL: $url');
if (duration != null) {
buffer.writeln('│ Duration: ${duration.inMilliseconds}ms');
}
if (headers != null && headers.isNotEmpty) {
buffer.writeln('│ Headers:');
headers.forEach((key, value) {
buffer.writeln('$key: $value');
});
}
if (body != null) {
buffer.writeln('│ Body: $body');
}
buffer.writeln('└─────────────────────────────────────────────────');
final color = statusCode >= 200 && statusCode < 300 ? _green : _red;
_log(LogLevel.debug, buffer.toString(), color: color);
}
}
/// Log d'un événement BLoC
static void blocEvent(String blocName, String eventName, {dynamic data}) {
if (AppConstants.enableLogging && kDebugMode) {
final message = data != null
? '[$blocName] Event: $eventName | Data: $data'
: '[$blocName] Event: $eventName';
_log(LogLevel.debug, message, color: _cyan);
}
}
/// Log d'un changement d'état BLoC
static void blocState(String blocName, String stateName, {dynamic data}) {
if (AppConstants.enableLogging && kDebugMode) {
final message = data != null
? '[$blocName] State: $stateName | Data: $data'
: '[$blocName] State: $stateName';
_log(LogLevel.debug, message, color: _magenta);
}
}
/// Log d'une navigation
static void navigation(String from, String to) {
if (AppConstants.enableLogging && kDebugMode) {
_log(LogLevel.debug, 'Navigation: $from$to', color: _yellow);
}
}
/// Log d'une action utilisateur
static void userAction(String action, {Map<String, dynamic>? data}) {
if (AppConstants.enableLogging && kDebugMode) {
final message = data != null
? 'User Action: $action | Data: $data'
: 'User Action: $action';
_log(LogLevel.info, message, color: _green);
}
// TODO: Envoyer à un service d'analytics
if (AppConstants.enableAnalytics) {
_sendToAnalytics(action, data);
}
}
/// Méthode privée pour logger avec formatage
static void _log(
LogLevel level,
String message, {
String? tag,
String color = _white,
}) {
final timestamp = DateTime.now().toIso8601String();
final levelStr = level.name.toUpperCase().padRight(7);
final tagStr = tag != null ? '[$tag] ' : '';
if (kDebugMode) {
// En mode debug, utiliser les couleurs
debugPrint('$color$timestamp | $levelStr | $tagStr$message$_reset');
} else {
// En mode release, pas de couleurs
debugPrint('$timestamp | $levelStr | $tagStr$message');
}
}
/// Envoyer les erreurs à un service de monitoring
static void _sendToMonitoring(
String message,
dynamic error,
StackTrace? stackTrace, {
bool isFatal = false,
}) {
// TODO: Implémenter l'envoi à Sentry, Firebase Crashlytics, etc.
// Exemple avec Sentry:
// Sentry.captureException(
// error,
// stackTrace: stackTrace,
// hint: Hint.withMap({'message': message}),
// );
}
/// Envoyer les événements à un service d'analytics
static void _sendToAnalytics(String action, Map<String, dynamic>? data) {
// TODO: Implémenter l'envoi à Firebase Analytics, Mixpanel, etc.
// Exemple avec Firebase Analytics:
// FirebaseAnalytics.instance.logEvent(
// name: action,
// parameters: data,
// );
}
/// Divider pour séparer visuellement les logs
static void divider({String? title}) {
if (AppConstants.enableLogging && kDebugMode) {
if (title != null) {
debugPrint('$_cyan═══════════════════════════════════════════════════$_reset');
debugPrint('$_cyan $title$_reset');
debugPrint('$_cyan═══════════════════════════════════════════════════$_reset');
} else {
debugPrint('$_cyan═══════════════════════════════════════════════════$_reset');
}
}
}
}
/// Extension pour faciliter le logging depuis n'importe où
extension LoggerExtension on Object {
/// Log debug
void logDebug(String message) {
AppLogger.debug(message, tag: runtimeType.toString());
}
/// Log info
void logInfo(String message) {
AppLogger.info(message, tag: runtimeType.toString());
}
/// Log warning
void logWarning(String message) {
AppLogger.warning(message, tag: runtimeType.toString());
}
/// Log error
void logError(String message, {dynamic error, StackTrace? stackTrace}) {
AppLogger.error(
message,
tag: runtimeType.toString(),
error: error,
stackTrace: stackTrace,
);
}
}