You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
133 lines
5.3 KiB
Dart
133 lines
5.3 KiB
Dart
import 'dart:io';
|
|
import 'package:hmg_qline/config/dependency_injection.dart';
|
|
import 'package:hmg_qline/constants/app_constants.dart';
|
|
import 'package:hmg_qline/services/cache_service.dart';
|
|
import 'package:hmg_qline/utilities/enums.dart';
|
|
import 'package:hmg_qline/view_models/screen_config_view_model.dart';
|
|
import 'package:intl/intl.dart';
|
|
import 'package:logger/logger.dart';
|
|
import 'package:path_provider/path_provider.dart';
|
|
|
|
abstract class LoggerService {
|
|
Future<void> logToFile({required String message, required LogTypeEnum type, required String source});
|
|
|
|
void logError(String message);
|
|
|
|
void logInfo(String message);
|
|
|
|
Future<void> logCrash({required Object error, StackTrace? stackTrace, String? context, String source = "CRASH"});
|
|
}
|
|
|
|
class LoggerServiceImp implements LoggerService {
|
|
Logger logger;
|
|
|
|
LoggerServiceImp({required this.logger});
|
|
|
|
Future<void> _ensureLogFileClearedIfNeeded({required File file, required DateTime now, required DateTime? lastLogsClearedAt, required String source, required String typeName}) async {
|
|
try {
|
|
CacheService cacheService = getIt.get<CacheService>();
|
|
|
|
// Clear by time threshold
|
|
if (lastLogsClearedAt != null && now.difference(lastLogsClearedAt).inHours >= AppConstants.clearLogsHoursThreshold) {
|
|
final clearingMessage = "[${DateFormat('yyyy-MM-dd hh:mm:ss a').format(now)}] [SOURCE: $source] $typeName: LOGS HAVE BEEN CLEARED\n";
|
|
await file.writeAsString(clearingMessage, mode: FileMode.write);
|
|
// persist
|
|
final updated = DateTime.now();
|
|
getIt.get<ScreenConfigViewModel>().lastTimeLogsCleared = updated;
|
|
await cacheService.setLastTimeLogsCleared(lastTimeCleared: updated.millisecondsSinceEpoch);
|
|
return;
|
|
}
|
|
|
|
// Clear by size threshold
|
|
if (await file.exists()) {
|
|
final length = await file.length();
|
|
if (length >= AppConstants.maxLogFileSizeBytes) {
|
|
final clearingMessage = "[${DateFormat('yyyy-MM-dd hh:mm:ss a').format(now)}] [SOURCE: $source] $typeName: LOGS ROTATED DUE_TO_SIZE\n";
|
|
// Overwrite file with clearing message
|
|
await file.writeAsString(clearingMessage, mode: FileMode.write);
|
|
final updated = DateTime.now();
|
|
getIt.get<ScreenConfigViewModel>().lastTimeLogsCleared = updated;
|
|
await cacheService.setLastTimeLogsCleared(lastTimeCleared: updated.millisecondsSinceEpoch);
|
|
return;
|
|
}
|
|
}
|
|
} catch (e) {
|
|
logger.e('Failed to check/clear log file: $e');
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<void> logToFile({required String message, required LogTypeEnum type, required String source}) async {
|
|
try {
|
|
ScreenConfigViewModel screenConfigViewModel = getIt.get<ScreenConfigViewModel>();
|
|
final timestamp = DateFormat('yyyy-MM-dd hh:mm:ss a').format(DateTime.now());
|
|
final formattedMessage = "[$timestamp] [SOURCE: $source] ${type.name.toUpperCase()}: $message";
|
|
|
|
final baseDir = await getExternalStorageDirectory();
|
|
final logDir = Directory('${baseDir!.path}/logs');
|
|
if (!await logDir.exists()) {
|
|
await logDir.create(recursive: true);
|
|
}
|
|
|
|
String logFileName = "";
|
|
|
|
if (type == LogTypeEnum.error) {
|
|
logFileName = AppStrings.errorLogsFileName;
|
|
} else if (type == LogTypeEnum.data) {
|
|
logFileName = AppStrings.dataLogsFileName;
|
|
} else {
|
|
logFileName = AppStrings.connectivityLogsFileName;
|
|
}
|
|
|
|
final file = File('${logDir.path}/${screenConfigViewModel.currentScreenIP}_$logFileName');
|
|
|
|
final now = DateTime.now();
|
|
await _ensureLogFileClearedIfNeeded(file: file, now: now, lastLogsClearedAt: screenConfigViewModel.lastTimeLogsCleared, source: source, typeName: type.name.toUpperCase());
|
|
|
|
await file.writeAsString("$formattedMessage\n", mode: FileMode.append);
|
|
} catch (e) {
|
|
logger.e('Logging failed: $e');
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<void> logCrash({required Object error, StackTrace? stackTrace, String? context, String source = "CRASH"}) async {
|
|
try {
|
|
ScreenConfigViewModel screenConfigViewModel = getIt.get<ScreenConfigViewModel>();
|
|
final timestamp = DateFormat('yyyy-MM-dd hh:mm:ss a').format(DateTime.now());
|
|
final sep = '==================== CRASH ====================';
|
|
final contextStr = context ?? 'No context provided';
|
|
final errorMsg = error.toString();
|
|
final stack = stackTrace?.toString() ?? 'No stack trace available';
|
|
|
|
final crashMessage = '$sep\n[$timestamp]\nCONTEXT: $contextStr\nERROR: $errorMsg\nSTACKTRACE:\n$stack\n$sep\n';
|
|
|
|
final baseDir = await getExternalStorageDirectory();
|
|
final logDir = Directory('${baseDir!.path}/logs');
|
|
if (!await logDir.exists()) {
|
|
await logDir.create(recursive: true);
|
|
}
|
|
|
|
final file = File('${logDir.path}/${screenConfigViewModel.currentScreenIP}_${AppStrings.errorLogsFileName}');
|
|
|
|
final now = DateTime.now();
|
|
await _ensureLogFileClearedIfNeeded(file: file, now: now, lastLogsClearedAt: screenConfigViewModel.lastTimeLogsCleared, source: source, typeName: 'ERROR');
|
|
|
|
await file.writeAsString(crashMessage, mode: FileMode.append);
|
|
logger.e('Crash logged: $errorMsg');
|
|
} catch (e) {
|
|
logger.e('Crash logging failed: $e');
|
|
}
|
|
}
|
|
|
|
@override
|
|
void logError(String message) {
|
|
logger.e(message);
|
|
}
|
|
|
|
@override
|
|
void logInfo(String message) {
|
|
logger.i(message);
|
|
}
|
|
}
|