TF-4136 refactor(logger): unify logging format and route error reporting
This commit is contained in:
+198
-53
@@ -1,70 +1,201 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'package:universal_html/html.dart' as html;
|
||||||
|
import 'package:core/utils/build_utils.dart';
|
||||||
import 'package:core/utils/platform_info.dart';
|
import 'package:core/utils/platform_info.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
final logHistory = _Dispatcher('');
|
/// ANSI escape colors (Web only)
|
||||||
|
const ansiReset = '\x1B[0m';
|
||||||
|
const ansiRed = '\x1B[31m';
|
||||||
|
const ansiYellow = '\x1B[33m';
|
||||||
|
const ansiGreen = '\x1B[32m';
|
||||||
|
const ansiBlue = '\x1B[34m';
|
||||||
|
const ansiBold = '\x1B[1m';
|
||||||
|
|
||||||
void log(String? value, {Level level = Level.info}) {
|
const appLogName = '[TwakeMail]';
|
||||||
if (!kDebugMode) return;
|
|
||||||
|
|
||||||
String logsStr = value ?? '';
|
String _applyWebColor(Level level, String text) {
|
||||||
logHistory.value = '$logsStr\n${logHistory.value}';
|
switch (level) {
|
||||||
|
case Level.wtf:
|
||||||
if (PlatformInfo.isWeb) {
|
return '$ansiRed$ansiBold!!!CRITICAL!!! $text$ansiReset';
|
||||||
switch (level) {
|
case Level.error:
|
||||||
case Level.wtf:
|
return '$ansiRed$text$ansiReset';
|
||||||
logsStr = '\x1B[31m!!!CRITICAL!!! $logsStr\x1B[0m';
|
case Level.warning:
|
||||||
break;
|
return '$ansiYellow$text$ansiReset';
|
||||||
case Level.error:
|
case Level.info:
|
||||||
logsStr = '\x1B[31m$logsStr\x1B[0m';
|
return '$ansiGreen$text$ansiReset';
|
||||||
break;
|
case Level.debug:
|
||||||
case Level.warning:
|
return '$ansiBlue$text$ansiReset';
|
||||||
logsStr = '\x1B[33m$logsStr\x1B[0m';
|
case Level.verbose:
|
||||||
break;
|
return text;
|
||||||
case Level.info:
|
|
||||||
logsStr = '\x1B[32m$logsStr\x1B[0m';
|
|
||||||
break;
|
|
||||||
case Level.debug:
|
|
||||||
logsStr = '\x1B[34m$logsStr\x1B[0m';
|
|
||||||
break;
|
|
||||||
case Level.verbose:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch (level) {
|
|
||||||
case Level.error:
|
|
||||||
logsStr = '[ERROR] $logsStr';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _applyMobileFormat(Level level, String text) {
|
||||||
|
switch (level) {
|
||||||
|
case Level.wtf:
|
||||||
|
return '🔥 CRITICAL: $text';
|
||||||
|
case Level.error:
|
||||||
|
return '❌ ERROR: $text';
|
||||||
|
case Level.warning:
|
||||||
|
return '⚠️ WARNING: $text';
|
||||||
|
case Level.info:
|
||||||
|
return 'ℹ️ INFO: $text';
|
||||||
|
case Level.debug:
|
||||||
|
return '🐛 DEBUG: $text';
|
||||||
|
case Level.verbose:
|
||||||
|
return '🔍 VERBOSE: $text';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _internalLog(
|
||||||
|
String? message, {
|
||||||
|
required Level level,
|
||||||
|
Object? exception,
|
||||||
|
StackTrace? stackTrace,
|
||||||
|
Map<String, dynamic>? extras,
|
||||||
|
bool webConsoleEnabled = false,
|
||||||
|
}) {
|
||||||
|
final rawMessage = _buildRawMessage(message, exception, extras, stackTrace);
|
||||||
|
final formattedMessage = _formatMessage(level, rawMessage);
|
||||||
|
|
||||||
|
if (webConsoleEnabled && PlatformInfo.isWeb) {
|
||||||
|
_printWebConsole(level, formattedMessage);
|
||||||
|
} else {
|
||||||
|
_debugPrint(formattedMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _buildRawMessage(
|
||||||
|
String? message,
|
||||||
|
Object? exception,
|
||||||
|
Map<String, dynamic>? extras,
|
||||||
|
StackTrace? stackTrace,
|
||||||
|
) {
|
||||||
|
final parts = <String>[];
|
||||||
|
if (message?.isNotEmpty == true) parts.add(message!);
|
||||||
|
if (exception != null) parts.add('exception: $exception');
|
||||||
|
if (extras != null && extras.isNotEmpty) parts.add('extras: $extras');
|
||||||
|
if (stackTrace != null) parts.add('stackTrace: $stackTrace');
|
||||||
|
return parts.join(' | ');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
String _formatMessage(Level level, String raw) {
|
||||||
|
return PlatformInfo.isWeb
|
||||||
|
? _applyWebColor(level, raw)
|
||||||
|
: _applyMobileFormat(level, raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _debugPrint(String formatted) {
|
||||||
|
if (!BuildUtils.isDebugMode) return;
|
||||||
|
|
||||||
// ignore: avoid_print
|
// ignore: avoid_print
|
||||||
print('[TwakeMail] $logsStr');
|
print('$appLogName $formatted');
|
||||||
}
|
}
|
||||||
|
|
||||||
void logError(String? value) => log(value, level: Level.error);
|
void _printWebConsole(Level level, String value) {
|
||||||
|
switch (level) {
|
||||||
// Take from: https://flutter.dev/docs/testing/errors
|
case Level.error:
|
||||||
void initLogger(VoidCallback runApp) {
|
case Level.wtf:
|
||||||
runZonedGuarded(() async {
|
html.window.console.error('$appLogName $value');
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
break;
|
||||||
FlutterError.onError = (details) {
|
case Level.warning:
|
||||||
FlutterError.dumpErrorToConsole(details);
|
html.window.console.warn('$appLogName $value');
|
||||||
logError('AppLogger::initLogger::runZonedGuarded:FlutterError.onError: ${details.stack.toString()}');
|
break;
|
||||||
};
|
case Level.info:
|
||||||
runApp.call();
|
html.window.console.info('$appLogName $value');
|
||||||
}, (error, stack) {
|
break;
|
||||||
logError('AppLogger::initLogger::runZonedGuarded:onError: $error | stack: $stack');
|
case Level.debug:
|
||||||
});
|
case Level.verbose:
|
||||||
|
html.window.console.debug('$appLogName $value');
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _Dispatcher extends ValueNotifier<String> {
|
void logError(
|
||||||
_Dispatcher(String value) : super(value);
|
String? message, {
|
||||||
|
Object? exception,
|
||||||
|
StackTrace? stackTrace,
|
||||||
|
Map<String, dynamic>? extras,
|
||||||
|
bool webConsoleEnabled = false,
|
||||||
|
}) {
|
||||||
|
_internalLog(
|
||||||
|
message,
|
||||||
|
level: Level.error,
|
||||||
|
exception: exception,
|
||||||
|
stackTrace: stackTrace,
|
||||||
|
extras: extras,
|
||||||
|
webConsoleEnabled: webConsoleEnabled,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void logWTF(
|
||||||
|
String? message, {
|
||||||
|
Object? exception,
|
||||||
|
StackTrace? stackTrace,
|
||||||
|
Map<String, dynamic>? extras,
|
||||||
|
bool webConsoleEnabled = false,
|
||||||
|
}) {
|
||||||
|
_internalLog(
|
||||||
|
message,
|
||||||
|
level: Level.wtf,
|
||||||
|
exception: exception,
|
||||||
|
stackTrace: stackTrace,
|
||||||
|
extras: extras,
|
||||||
|
webConsoleEnabled: webConsoleEnabled,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void logWarning(
|
||||||
|
String? message, {
|
||||||
|
bool webConsoleEnabled = false,
|
||||||
|
}) {
|
||||||
|
_internalLog(message,
|
||||||
|
level: Level.warning, webConsoleEnabled: webConsoleEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
void logInfo(
|
||||||
|
String? message, {
|
||||||
|
bool webConsoleEnabled = false,
|
||||||
|
}) {
|
||||||
|
_internalLog(
|
||||||
|
message,
|
||||||
|
level: Level.info,
|
||||||
|
webConsoleEnabled: webConsoleEnabled,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void logDebug(
|
||||||
|
String? message, {
|
||||||
|
bool webConsoleEnabled = false,
|
||||||
|
}) {
|
||||||
|
_internalLog(
|
||||||
|
message,
|
||||||
|
level: Level.debug,
|
||||||
|
webConsoleEnabled: webConsoleEnabled,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void logVerbose(
|
||||||
|
String? message, {
|
||||||
|
bool webConsoleEnabled = false,
|
||||||
|
}) {
|
||||||
|
_internalLog(
|
||||||
|
message,
|
||||||
|
level: Level.verbose,
|
||||||
|
webConsoleEnabled: webConsoleEnabled,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void log(
|
||||||
|
String? message, {
|
||||||
|
bool webConsoleEnabled = false,
|
||||||
|
}) =>
|
||||||
|
logInfo(
|
||||||
|
message,
|
||||||
|
webConsoleEnabled: webConsoleEnabled,
|
||||||
|
);
|
||||||
|
|
||||||
enum Level {
|
enum Level {
|
||||||
wtf,
|
wtf,
|
||||||
@@ -74,3 +205,17 @@ enum Level {
|
|||||||
debug,
|
debug,
|
||||||
verbose,
|
verbose,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Take from: https://flutter.dev/docs/testing/errors
|
||||||
|
void initLogger(VoidCallback runApp) {
|
||||||
|
runZonedGuarded(() async {
|
||||||
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
FlutterError.onError = (details) {
|
||||||
|
FlutterError.dumpErrorToConsole(details);
|
||||||
|
logWarning('AppLogger::initLogger::runZonedGuarded:FlutterError.onError: ${details.stack.toString()}');
|
||||||
|
};
|
||||||
|
runApp.call();
|
||||||
|
}, (error, stack) {
|
||||||
|
logWarning('AppLogger::initLogger::runZonedGuarded:onError: $error | stack: $stack');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user