// hey import 'dart:async'; import 'dart:convert'; import 'package:flutter/foundation.dart'; enum LogLevel { debug, info, warning, error, critical } class ConnectionLogger { static final ConnectionLogger _instance = ConnectionLogger._internal(); factory ConnectionLogger() => _instance; ConnectionLogger._internal(); final List _logs = []; final StreamController _logController = StreamController.broadcast(); Stream get logStream => _logController.stream; List get logs => List.unmodifiable(_logs); static const int maxLogs = 1000; LogLevel _currentLevel = LogLevel.debug; void setLogLevel(LogLevel level) { _currentLevel = level; } void log( String message, { LogLevel level = LogLevel.info, String? category, Map? data, Object? error, StackTrace? stackTrace, }) { if (level.index < _currentLevel.index) return; final entry = LogEntry( timestamp: DateTime.now(), level: level, message: message, category: category ?? 'CONNECTION', data: data, error: error, stackTrace: stackTrace, ); _logs.add(entry); if (_logs.length > maxLogs) { _logs.removeRange(0, _logs.length - maxLogs); } _logController.add(entry); if (kDebugMode) { final emoji = _getEmojiForLevel(level); final timestamp = entry.timestamp.toIso8601String().substring(11, 23); final categoryStr = category != null ? '[$category]' : ''; final dataStr = data != null ? ' | Data: ${jsonEncode(data)}' : ''; final errorStr = error != null ? ' | Error: $error' : ''; print('$emoji [$timestamp] $categoryStr $message$dataStr$errorStr'); } } void logConnection( String message, { Map? data, Object? error, }) { log( message, level: LogLevel.info, category: 'CONNECTION', data: data, error: error, ); } void logError( String message, { Map? data, Object? error, StackTrace? stackTrace, }) { log( message, level: LogLevel.error, category: 'ERROR', data: data, error: error, stackTrace: stackTrace, ); } void logMessage( String direction, dynamic message, { Map? metadata, }) { final data = { 'direction': direction, 'message': message, if (metadata != null) ...metadata, }; log( 'WebSocket $direction', level: LogLevel.debug, category: 'WEBSOCKET', data: data, ); } void logReconnect(int attempt, String reason, {Duration? delay}) { final data = { 'attempt': attempt, 'reason': reason, if (delay != null) 'delay_seconds': delay.inSeconds, }; log( 'Переподключение: $reason (попытка $attempt)', level: LogLevel.warning, category: 'RECONNECT', data: data, ); } void logPerformance( String operation, Duration duration, { Map? metadata, }) { final data = { 'operation': operation, 'duration_ms': duration.inMilliseconds, if (metadata != null) ...metadata, }; log( 'Performance: $operation за ${duration.inMilliseconds}ms', level: LogLevel.debug, category: 'PERFORMANCE', data: data, ); } // If you're touching ( you doing this rignt now ) this file, STOP IMEDIATLY! This is violiating TeamKomet code revision policy! // If you're touching ( you doing this rignt now ) this file, AND DONT WANT TO STOP! REFACTOR IT IMMEDIATLY TO MAKE SOME SENSE AND DONT LOOK LIKE SHIT BY AI void logState(String from, String to, {Map? metadata}) { final data = { 'from': from, 'to': to, if (metadata != null) ...metadata, }; log( 'Состояние: $from → $to', level: LogLevel.info, category: 'STATE', data: data, ); } List getLogsByCategory(String category) { return _logs.where((log) => log.category == category).toList(); } List getLogsByLevel(LogLevel level) { return _logs.where((log) => log.level == level).toList(); } Map getLogStats() { final stats = {}; for (final log in _logs) { stats[log.category] = (stats[log.category] ?? 0) + 1; } return stats; } void clearLogs() { _logs.clear(); log('Логи очищены', level: LogLevel.info, category: 'LOGGER'); } String exportLogs() { final logsJson = _logs.map((log) => log.toJson()).toList(); return jsonEncode(logsJson); } void importLogs(String jsonString) { try { final List logsList = jsonDecode(jsonString); _logs.clear(); for (final logJson in logsList) { _logs.add(LogEntry.fromJson(logJson)); } log( 'Импортировано ${_logs.length} логов', level: LogLevel.info, category: 'LOGGER', ); } catch (e) { logError('Ошибка импорта логов', error: e); } } String _getEmojiForLevel(LogLevel level) { switch (level) { case LogLevel.debug: return '🔍'; case LogLevel.info: return 'ℹ️'; case LogLevel.warning: return '⚠️'; case LogLevel.error: return '❌'; case LogLevel.critical: return '🚨'; } } void dispose() { _logController.close(); } } class LogEntry { final DateTime timestamp; final LogLevel level; final String message; final String category; final Map? data; final Object? error; final StackTrace? stackTrace; LogEntry({ required this.timestamp, required this.level, required this.message, required this.category, this.data, this.error, this.stackTrace, }); Map toJson() { return { 'timestamp': timestamp.toIso8601String(), 'level': level.name, 'message': message, 'category': category, 'data': data, 'error': error?.toString(), 'stackTrace': stackTrace?.toString(), }; } factory LogEntry.fromJson(Map json) { return LogEntry( timestamp: DateTime.parse(json['timestamp']), level: LogLevel.values.firstWhere((l) => l.name == json['level']), message: json['message'], category: json['category'], data: json['data'] != null ? Map.from(json['data']) : null, error: json['error'], stackTrace: json['stackTrace'] != null ? StackTrace.fromString(json['stackTrace']) : null, ); } @override String toString() { final emoji = _getEmojiForLevel(level); final timestamp = this.timestamp.toIso8601String().substring(11, 23); final dataStr = data != null ? ' | Data: ${jsonEncode(data)}' : ''; final errorStr = error != null ? ' | Error: $error' : ''; return '$emoji [$timestamp] [$category] $message$dataStr$errorStr'; } String _getEmojiForLevel(LogLevel level) { switch (level) { case LogLevel.debug: return '🔍'; case LogLevel.info: return 'ℹ️'; case LogLevel.warning: return '⚠️'; case LogLevel.error: return '❌'; case LogLevel.critical: return '🚨'; } } }