From 2288192975050eb3b6bcf02048fd4158154e04f0 Mon Sep 17 00:00:00 2001 From: Faiz Hashmi Date: Mon, 4 Aug 2025 16:20:08 +0300 Subject: [PATCH] improved Logging (8.2) --- lib/constants/app_constants.dart | 5 ++-- lib/repositories/screen_details_repo.dart | 18 ++++++------ lib/repositories/signalR_repo.dart | 7 +++-- lib/services/cache_service.dart | 28 ++++++++++++++++--- lib/services/logger_service.dart | 20 ++++++++++--- lib/utilities/native_method_handler.dart | 4 +-- lib/view_models/queuing_view_model.dart | 8 +++--- lib/view_models/screen_config_view_model.dart | 14 ++++++++-- 8 files changed, 74 insertions(+), 30 deletions(-) diff --git a/lib/constants/app_constants.dart b/lib/constants/app_constants.dart index 41a286c..d363a9b 100644 --- a/lib/constants/app_constants.dart +++ b/lib/constants/app_constants.dart @@ -24,7 +24,6 @@ class AppStrings { static String dataLogsFileName = "data_logs.txt"; static String errorLogsFileName = "error_logs.txt"; - static String openAppNativeFunctionName = "reopenApp"; } @@ -107,7 +106,8 @@ class AppConstants { static String testIP = '12.4.5.1'; // projectID.QlineType.ScreenType.AnyNumber (1 to 10) static int thresholdForListUI = 3; - static double currentBuildVersion = 8.1; + static double currentBuildVersion = 8.2; + static double clearLogsHoursThreshold = 48; } class ApiConstants { @@ -144,6 +144,7 @@ class ApiConstants { class CacheConstants { static String lastTimeUpdated = "lastTimeUpdated"; + static String logLastCleared = "log_last_cleared"; } // calling for pharmacy diff --git a/lib/repositories/screen_details_repo.dart b/lib/repositories/screen_details_repo.dart index 689723e..f873fee 100644 --- a/lib/repositories/screen_details_repo.dart +++ b/lib/repositories/screen_details_repo.dart @@ -49,14 +49,14 @@ class ScreenDetailsRepoImp implements ScreenDetailsRepo { ); List globalConfigurationsModel = List.generate(genericModel.data.length, (index) => GlobalConfigurationsModel.fromJson(json: genericModel.data[index])); if (globalConfigurationsModel.isNotEmpty) { - loggerService.logToFile(globalConfigurationsModel.toString(), type: LogTypeEnum.data); + loggerService.logToFile(message: globalConfigurationsModel.toString(), type: LogTypeEnum.data, source: "getGlobalScreenConfigurations-> screen_details_repo.dart"); return globalConfigurationsModel.first; } return null; } catch (e) { loggerService.logError(e.toString()); - loggerService.logToFile(e.toString(), type: LogTypeEnum.error); + loggerService.logToFile(message: e.toString(), source: "getGlobalScreenConfigurations-> screen_details_repo.dart", type: LogTypeEnum.error); InfoComponents.showToast(e.toString()); return null; } @@ -82,7 +82,7 @@ class ScreenDetailsRepoImp implements ScreenDetailsRepo { return genericModel; } catch (e) { loggerService.logError(e.toString()); - loggerService.logToFile(e.toString(), type: LogTypeEnum.error); + loggerService.logToFile(message: e.toString(), source: "createTestTickets-> screen_details_repo.dart", type: LogTypeEnum.error); InfoComponents.showToast(e.toString()); return null; } @@ -109,7 +109,7 @@ class ScreenDetailsRepoImp implements ScreenDetailsRepo { return genericRespModel; } catch (e) { loggerService.logError(e.toString()); - loggerService.logToFile(e.toString(), type: LogTypeEnum.error); + loggerService.logToFile(message: e.toString(), source: "createTicketFromKiosk-> screen_details_repo.dart", type: LogTypeEnum.error); InfoComponents.showToast(e.toString()); return null; } @@ -132,7 +132,7 @@ class ScreenDetailsRepoImp implements ScreenDetailsRepo { return null; } catch (e) { loggerService.logError(e.toString()); - loggerService.logToFile(e.toString(), type: LogTypeEnum.error); + loggerService.logToFile(message: e.toString(), source: "getWeatherDetailsByCity-> screen_details_repo.dart", type: LogTypeEnum.error); InfoComponents.showToast(e.toString()); return null; } @@ -156,7 +156,7 @@ class ScreenDetailsRepoImp implements ScreenDetailsRepo { return null; } catch (e) { loggerService.logError(e.toString()); - loggerService.logToFile(e.toString(), type: LogTypeEnum.error); + loggerService.logToFile(message: e.toString(), source: "getPrayerDetailsByLatLong-> screen_details_repo.dart", type: LogTypeEnum.error); InfoComponents.showToast(e.toString()); return null; } @@ -179,7 +179,7 @@ class ScreenDetailsRepoImp implements ScreenDetailsRepo { return null; } catch (e) { loggerService.logError(e.toString()); - loggerService.logToFile(e.toString(), type: LogTypeEnum.error); + loggerService.logToFile(message: e.toString(), source: "getRssFeedDetailsByLanguageID-> screen_details_repo.dart", type: LogTypeEnum.error); InfoComponents.showToast(e.toString()); return null; } @@ -201,7 +201,7 @@ class ScreenDetailsRepoImp implements ScreenDetailsRepo { return genericModel; } catch (e) { loggerService.logError(e.toString()); - loggerService.logToFile(e.toString(), type: LogTypeEnum.error); + loggerService.logToFile(message: e.toString(), source: "acknowledgeTicket-> screen_details_repo.dart", type: LogTypeEnum.error); InfoComponents.showToast(e.toString()); return null; } @@ -225,7 +225,7 @@ class ScreenDetailsRepoImp implements ScreenDetailsRepo { return genericModel; } catch (e) { loggerService.logError(e.toString()); - loggerService.logToFile(e.toString(), type: LogTypeEnum.error); + loggerService.logToFile(message: e.toString(), source: "acknowledgeTicketForAppointment-> screen_details_repo.dart", type: LogTypeEnum.error); InfoComponents.showToast(e.toString()); return null; } diff --git a/lib/repositories/signalR_repo.dart b/lib/repositories/signalR_repo.dart index a03e232..2956aa8 100644 --- a/lib/repositories/signalR_repo.dart +++ b/lib/repositories/signalR_repo.dart @@ -57,11 +57,12 @@ class SignalrRepoImp implements SignalrRepo { // Attempt to reconnect with limit and delay if (reconnectAttempts < maxReconnectAttempts) { reconnectAttempts++; - loggerService.logToFile("SignalR reconnect attempt #$reconnectAttempts", type: LogTypeEnum.data); + loggerService.logToFile(message: "SignalR reconnect attempt #$reconnectAttempts", source: "startHubConnection -> signalR_repo.dart", type: LogTypeEnum.data); + await Future.delayed(reconnectDelay); try { await connection!.start(); - loggerService.logToFile("SignalR reconnected after disconnect", type: LogTypeEnum.data); + loggerService.logToFile(message: "SignalR reconnected after disconnect", source: "startHubConnection -> signalR_repo.dart", type: LogTypeEnum.data); reconnectAttempts = 0; // Reset on success } catch (e) { loggerService.logError("Reconnect failed: $e"); @@ -89,7 +90,7 @@ class SignalrRepoImp implements SignalrRepo { return true; } catch (e) { loggerService.logError(e.toString()); - loggerService.logToFile(e.toString(), type: LogTypeEnum.error); + loggerService.logToFile(message: e.toString(), source: "startHubConnection -> signalR_repo.dart", type: LogTypeEnum.error); return false; } } diff --git a/lib/services/cache_service.dart b/lib/services/cache_service.dart index 5cbdda3..2560bfe 100644 --- a/lib/services/cache_service.dart +++ b/lib/services/cache_service.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:hmg_qline/constants/app_constants.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -5,6 +7,10 @@ abstract class CacheService { Future getLastTimeUpdatedFromCache(); Future setLastTimeUpdatedInCache({required String lasTimeUpdated}); + + Future setLastTimeLogsCleared({required int lastTimeCleared}); + + Future getLastTimeLogsCleared(); } class CacheServiceImp implements CacheService { @@ -14,10 +20,8 @@ class CacheServiceImp implements CacheService { @override Future getLastTimeUpdatedFromCache() async { - final SharedPreferences prefs = await SharedPreferences.getInstance(); - - if (prefs.containsKey(CacheConstants.lastTimeUpdated)) { - String? lastTimeUpdated = prefs.getString(CacheConstants.lastTimeUpdated); + if (preferencesInstance.containsKey(CacheConstants.lastTimeUpdated)) { + String? lastTimeUpdated = preferencesInstance.getString(CacheConstants.lastTimeUpdated); DateTime currentLastTimeUpdated = DateTime.fromMillisecondsSinceEpoch(int.parse(lastTimeUpdated!)); return currentLastTimeUpdated; } else { @@ -29,4 +33,20 @@ class CacheServiceImp implements CacheService { Future setLastTimeUpdatedInCache({required String lasTimeUpdated}) async { await preferencesInstance.setString(CacheConstants.lastTimeUpdated, lasTimeUpdated); } + + @override + Future getLastTimeLogsCleared() async { + if (preferencesInstance.containsKey(CacheConstants.lastTimeUpdated)) { + String? lastTimeUpdated = preferencesInstance.getString(CacheConstants.lastTimeUpdated); + DateTime currentLastTimeUpdated = DateTime.fromMillisecondsSinceEpoch(int.parse(lastTimeUpdated!)); + return currentLastTimeUpdated; + } else { + return null; + } + } + + @override + Future setLastTimeLogsCleared({required int lastTimeCleared}) async { + await preferencesInstance.setInt(CacheConstants.lastTimeUpdated, lastTimeCleared); + } } diff --git a/lib/services/logger_service.dart b/lib/services/logger_service.dart index ee65a83..a320dc8 100644 --- a/lib/services/logger_service.dart +++ b/lib/services/logger_service.dart @@ -1,12 +1,15 @@ 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 logToFile(String message, {LogTypeEnum type = LogTypeEnum.data}); + Future logToFile({required String message, required LogTypeEnum type, required String source}); Future clearLogs(); @@ -21,10 +24,10 @@ class LoggerServiceImp implements LoggerService { LoggerServiceImp({required this.logger}); @override - Future logToFile(String message, {LogTypeEnum type = LogTypeEnum.data}) async { + Future logToFile({required String message, required LogTypeEnum type, required String source}) async { try { final timestamp = DateFormat('yyyy-MM-dd hh:mm:ss a').format(DateTime.now()); - final formattedMessage = "[$timestamp] ${type.name.toUpperCase()}: $message"; + final formattedMessage = "[$timestamp] [SOURCE: $source] ${type.name.toUpperCase()}: $message"; final dir = await getApplicationDocumentsDirectory(); final logDir = Directory('${dir.path}/logs'); @@ -35,9 +38,18 @@ class LoggerServiceImp implements LoggerService { final logFileName = type == LogTypeEnum.error ? AppStrings.errorLogsFileName : AppStrings.dataLogsFileName; final file = File('${logDir.path}/$logFileName'); + ScreenConfigViewModel screenConfigViewModel = getIt.get(); + CacheService cacheService = getIt.get(); + final lastLogsClearedAt = screenConfigViewModel.lastTimeLogsCleared; + final now = DateTime.now(); + if (lastLogsClearedAt != null && now.difference(lastLogsClearedAt).inHours >= AppConstants.clearLogsHoursThreshold) { + await file.writeAsString(''); + getIt.get().lastTimeLogsCleared = now; + cacheService.setLastTimeLogsCleared(lastTimeCleared: now.millisecondsSinceEpoch); + } await file.writeAsString("$formattedMessage\n", mode: FileMode.append); } catch (e) { - logger.i('Logging failed: $e'); + logger.e('Logging failed: $e'); } } diff --git a/lib/utilities/native_method_handler.dart b/lib/utilities/native_method_handler.dart index bec0cfd..1a5dc5a 100644 --- a/lib/utilities/native_method_handler.dart +++ b/lib/utilities/native_method_handler.dart @@ -22,7 +22,7 @@ class NativeMethodChannelServiceImp implements NativeMethodChannelService { await platform.invokeMethod(AppStrings.openAppNativeFunctionName); } catch (e) { loggerService.logError("Error launching app: $e"); - loggerService.logToFile("Error launching app: $e", type: LogTypeEnum.error); + loggerService.logToFile(message: "Error launching app: $e", source: "reopenApp -> native_method_handler.dart ", type: LogTypeEnum.error); } } @@ -32,7 +32,7 @@ class NativeMethodChannelServiceImp implements NativeMethodChannelService { await Restart.restartApp(); } catch (e) { loggerService.logError("Error restarting App : $e"); - loggerService.logToFile("Error restarting App : $e", type: LogTypeEnum.error); + loggerService.logToFile(message: "Error restarting app: $e", source: "restartApp -> native_method_handler.dart ", type: LogTypeEnum.error); } } } diff --git a/lib/view_models/queuing_view_model.dart b/lib/view_models/queuing_view_model.dart index 5e9b9f8..6804fae 100644 --- a/lib/view_models/queuing_view_model.dart +++ b/lib/view_models/queuing_view_model.dart @@ -58,7 +58,7 @@ class QueuingViewModel extends ChangeNotifier { } Future onHubConfigCall(var response) async { - loggerService.logToFile(response.toString(), type: LogTypeEnum.data); + loggerService.logToFile(message: response.toString(), source: "onHubConfigCall -> queueing_view_model.dart ", type: LogTypeEnum.data); if (response != null && response.isNotEmpty) { var data = response.first['data']; @@ -76,7 +76,7 @@ class QueuingViewModel extends ChangeNotifier { } Future onHubTicketCall(List? response) async { - loggerService.logToFile(response.toString(), type: LogTypeEnum.data); + loggerService.logToFile(message: response.toString(), source: "onHubTicketCall -> queueing_view_model.dart ", type: LogTypeEnum.data); log("onHubTicketCall: $response"); @@ -89,7 +89,7 @@ class QueuingViewModel extends ChangeNotifier { Future onHubReconnected(var response) async { log("onHubConnected: $response"); - loggerService.logToFile("onHubConnected", type: LogTypeEnum.data); + loggerService.logToFile(message: response.toString(), source: "onHubReconnected -> queueing_view_model.dart ", type: LogTypeEnum.data); ScreenConfigViewModel screenConfigViewModel = getIt.get(); screenConfigViewModel.updateIsHubConnected(true); @@ -98,7 +98,7 @@ class QueuingViewModel extends ChangeNotifier { Future onHubDisconnected(var response) async { log("onHubDisconnected: $response"); - loggerService.logToFile("onHubDisconnected", type: LogTypeEnum.data); + loggerService.logToFile(message: response.toString(), source: "onHubDisconnected -> queueing_view_model.dart ", type: LogTypeEnum.data); ScreenConfigViewModel screenConfigViewModel = getIt.get(); screenConfigViewModel.updateIsHubConnected(false); diff --git a/lib/view_models/screen_config_view_model.dart b/lib/view_models/screen_config_view_model.dart index 39a25b0..5e56d2e 100644 --- a/lib/view_models/screen_config_view_model.dart +++ b/lib/view_models/screen_config_view_model.dart @@ -43,16 +43,17 @@ class ScreenConfigViewModel extends ChangeNotifier { Future initializeScreenConfigVM() async { await getGlobalConfigurationsByIP(); await getLastTimeUpdatedFromCache(); + await getLastTimeLogsClearedFromCache(); listenNetworkConnectivity(); getTheWidgetsConfigurationsEveryMidnight(); } Future onAppResumed() async { - loggerService.logToFile("[didChangeAppLifecycleState] : [onAppResumed]", type: LogTypeEnum.data); + loggerService.logToFile(message: "[didChangeAppLifecycleState] : [onAppResumed]", source: "onAppResumed -> screen_config_view_model.dart", type: LogTypeEnum.data); } Future onAppPaused() async { - loggerService.logToFile("[didChangeAppLifecycleState] : [onAppPaused]", type: LogTypeEnum.data); + loggerService.logToFile(message: "[didChangeAppLifecycleState] : [onAppPaused]", source: "onAppPaused -> screen_config_view_model.dart", type: LogTypeEnum.data); // nativeMethodChannelService.reopenApp(); nativeMethodChannelService.restartApp(); @@ -343,6 +344,15 @@ class ScreenConfigViewModel extends ChangeNotifier { } } + DateTime? lastTimeLogsCleared = DateTime.now(); + + Future getLastTimeLogsClearedFromCache() async { + lastTimeLogsCleared = await cacheService.getLastTimeLogsCleared(); + if (lastTimeLogsCleared == null) { + await cacheService.setLastTimeLogsCleared(lastTimeCleared: DateTime.now().millisecondsSinceEpoch).whenComplete(() => lastTimeLogsCleared = DateTime.now()); + } + } + // *************************** KIOSK FUNCTIONS ************************* KioskScreenStateEnums kioskScreenStateEnum = KioskScreenStateEnums.languageState;