File size: 8,912 Bytes
7dadc22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
import 'dart:developer' as developer;
import 'package:flutter/foundation.dart';

/// ANSI color codes for terminal output
class AnsiColors {
  static const String reset = '\x1B[0m';
  static const String bold = '\x1B[1m';
  static const String dim = '\x1B[2m';
  static const String italic = '\x1B[3m';
  static const String underline = '\x1B[4m';

  // Foreground colors
  static const String black = '\x1B[30m';
  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';

  // Bright foreground colors
  static const String brightBlack = '\x1B[90m';
  static const String brightRed = '\x1B[91m';
  static const String brightGreen = '\x1B[92m';
  static const String brightYellow = '\x1B[93m';
  static const String brightBlue = '\x1B[94m';
  static const String brightMagenta = '\x1B[95m';
  static const String brightCyan = '\x1B[96m';
  static const String brightWhite = '\x1B[97m';

  // Background colors
  static const String bgBlack = '\x1B[40m';
  static const String bgRed = '\x1B[41m';
  static const String bgGreen = '\x1B[42m';
  static const String bgYellow = '\x1B[43m';
  static const String bgBlue = '\x1B[44m';
  static const String bgMagenta = '\x1B[45m';
  static const String bgCyan = '\x1B[46m';
  static const String bgWhite = '\x1B[47m';
}

/// Log levels with associated colors and emojis
enum LogLevel {
  debug(AnsiColors.brightBlack, 'πŸ”', 'DEBUG'),
  info(AnsiColors.brightCyan, 'πŸ’‘', 'INFO'),
  warning(AnsiColors.brightYellow, '⚠️', 'WARN'),
  error(AnsiColors.brightRed, '❌', 'ERROR'),
  success(AnsiColors.brightGreen, 'βœ…', 'SUCCESS'),
  network(AnsiColors.brightMagenta, '🌐', 'NET'),
  websocket(AnsiColors.cyan, 'πŸ”Œ', 'WS'),
  video(AnsiColors.brightBlue, '🎬', 'VIDEO'),
  chat(AnsiColors.green, 'πŸ’¬', 'CHAT'),
  search(AnsiColors.yellow, 'πŸ”', 'SEARCH');

  const LogLevel(this.color, this.emoji, this.label);
  
  final String color;
  final String emoji;
  final String label;
}

/// Beautiful colored logger for Flutter applications
class ColoredLogger {
  final String _className;
  
  ColoredLogger(this._className);
  
  /// Create a logger for a specific class
  static ColoredLogger get(String className) {
    return ColoredLogger(className);
  }
  
  /// Debug level logging - for detailed debugging info
  void debug(String message, [Map<String, dynamic>? data]) {
    _log(LogLevel.debug, message, data);
  }
  
  /// Info level logging - for general information
  void info(String message, [Map<String, dynamic>? data]) {
    _log(LogLevel.info, message, data);
  }
  
  /// Warning level logging - for potential issues
  void warning(String message, [Map<String, dynamic>? data]) {
    _log(LogLevel.warning, message, data);
  }
  
  /// Error level logging - for errors and exceptions
  void error(String message, [Map<String, dynamic>? data]) {
    _log(LogLevel.error, message, data);
  }
  
  /// Success level logging - for successful operations
  void success(String message, [Map<String, dynamic>? data]) {
    _log(LogLevel.success, message, data);
  }
  
  /// Network level logging - for network operations
  void network(String message, [Map<String, dynamic>? data]) {
    _log(LogLevel.network, message, data);
  }
  
  /// WebSocket level logging - for WebSocket operations
  void websocket(String message, [Map<String, dynamic>? data]) {
    _log(LogLevel.websocket, message, data);
  }
  
  /// Video level logging - for video generation operations
  void video(String message, [Map<String, dynamic>? data]) {
    _log(LogLevel.video, message, data);
  }
  
  /// Chat level logging - for chat operations
  void chat(String message, [Map<String, dynamic>? data]) {
    _log(LogLevel.chat, message, data);
  }
  
  /// Search level logging - for search operations
  void search(String message, [Map<String, dynamic>? data]) {
    _log(LogLevel.search, message, data);
  }
  
  void _log(LogLevel level, String message, Map<String, dynamic>? data) {
    if (!kDebugMode) return; // Only log in debug mode
    
    final timestamp = DateTime.now();
    final timeStr = '${timestamp.hour.toString().padLeft(2, '0')}:'
                   '${timestamp.minute.toString().padLeft(2, '0')}:'
                   '${timestamp.second.toString().padLeft(2, '0')}.'
                   '${timestamp.millisecond.toString().padLeft(3, '0')}';
    
    // Format the main log message with colors
    final coloredMessage = _colorizeMessage(message);
    
    // Build the log line
    final logLine = StringBuffer();
    
    // Timestamp (dim)
    logLine.write('${AnsiColors.dim}$timeStr${AnsiColors.reset} ');
    
    // Level with color and emoji
    logLine.write('${level.color}${level.emoji} ${level.label.padRight(7)}${AnsiColors.reset} ');
    
    // Class name (bright black)
    logLine.write('${AnsiColors.brightBlack}[$_className]${AnsiColors.reset} ');
    
    // Message
    logLine.write(coloredMessage);
    
    // Add data if provided
    if (data != null && data.isNotEmpty) {
      logLine.write(' ${AnsiColors.dim}${_formatData(data)}${AnsiColors.reset}');
    }
    
    // Use developer.log for better IDE integration
    developer.log(
      logLine.toString(),
      name: _className,
      level: _getLevelValue(level),
    );
  }
  
  String _colorizeMessage(String message) {
    String result = message;
    
    // Highlight request IDs in brackets
    result = result.replaceAllMapped(
      RegExp(r'\[([a-zA-Z0-9-]+)\]'),
      (match) => '${AnsiColors.brightGreen}[${match.group(1)}]${AnsiColors.reset}',
    );
    
    // Highlight user IDs
    result = result.replaceAllMapped(
      RegExp(r'\buser ([a-zA-Z0-9-]+)'),
      (match) => 'user ${AnsiColors.brightBlue}${match.group(1)}${AnsiColors.reset}',
    );
    
    // Highlight actions
    result = result.replaceAllMapped(
      RegExp(r'\b(generate_video|search|simulate|join_chat|leave_chat|chat_message|connect|disconnect)\b'),
      (match) => '${AnsiColors.brightYellow}${match.group(1)}${AnsiColors.reset}',
    );
    
    // Highlight status keywords
    result = result.replaceAllMapped(
      RegExp(r'\b(success|successful|completed|connected|ready|ok)\b', caseSensitive: false),
      (match) => '${AnsiColors.brightGreen}${match.group(1)}${AnsiColors.reset}',
    );
    
    result = result.replaceAllMapped(
      RegExp(r'\b(error|failed|timeout|exception|crash)\b', caseSensitive: false),
      (match) => '${AnsiColors.brightRed}${match.group(1)}${AnsiColors.reset}',
    );
    
    result = result.replaceAllMapped(
      RegExp(r'\b(warning|retry|reconnect|fallback)\b', caseSensitive: false),
      (match) => '${AnsiColors.brightYellow}${match.group(1)}${AnsiColors.reset}',
    );
    
    // Highlight numbers with units
    result = result.replaceAllMapped(
      RegExp(r'\b(\d+\.?\d*)(ms|s|MB|KB|bytes|chars|fps)?\b'),
      (match) => '${AnsiColors.brightMagenta}${match.group(1)}${AnsiColors.cyan}${match.group(2) ?? ''}${AnsiColors.reset}',
    );
    
    // Highlight URLs
    result = result.replaceAllMapped(
      RegExp(r'https?://[^\s]+'),
      (match) => '${AnsiColors.underline}${AnsiColors.brightCyan}${match.group(0)}${AnsiColors.reset}',
    );
    
    // Highlight JSON-like structures
    result = result.replaceAllMapped(
      RegExp(r'\{[^}]*\}'),
      (match) => '${AnsiColors.dim}${match.group(0)}${AnsiColors.reset}',
    );
    
    // Highlight strings in quotes
    result = result.replaceAllMapped(
      RegExp(r'"([^"]*)"'),
      (match) => '"${AnsiColors.green}${match.group(1)}${AnsiColors.reset}"',
    );
    
    return result;
  }
  
  String _formatData(Map<String, dynamic> data) {
    final entries = data.entries.map((e) {
      final key = e.key;
      final value = e.value.toString();
      return '${AnsiColors.cyan}$key${AnsiColors.reset}=${AnsiColors.brightWhite}$value${AnsiColors.reset}';
    }).join(' ');
    
    return '{$entries}';
  }
  
  int _getLevelValue(LogLevel level) {
    switch (level) {
      case LogLevel.debug:
        return 500;
      case LogLevel.info:
        return 800;
      case LogLevel.warning:
        return 900;
      case LogLevel.error:
        return 1000;
      case LogLevel.success:
        return 800;
      case LogLevel.network:
        return 700;
      case LogLevel.websocket:
        return 700;
      case LogLevel.video:
        return 700;
      case LogLevel.chat:
        return 700;
      case LogLevel.search:
        return 700;
    }
  }
}

/// Extension methods for easy logging
extension ColoredLogging on Object {
  ColoredLogger get log => ColoredLogger.get(runtimeType.toString());
}

/// Global logger instance for quick access
final appLog = ColoredLogger.get('App');