// ignore_for_file: deprecated_member_use import 'dart:developer' as developer; import 'package:flutter/foundation.dart'; import 'package:onufitness/environment/app_environment.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; class LoggerService { static final LoggerService _instance = LoggerService._internal(); factory LoggerService() { return _instance; } LoggerService._internal(); //................................................................................................ void log( String message, { String? name, Object? error, StackTrace? stackTrace, Map? extras, }) { if (AppEnvironment.isDevelopment) { // Use dart:developer log for production (inverted for testing) developer.log( message, name: name ?? 'App', error: error, stackTrace: stackTrace, ); // Also print extras if provided if (extras != null && extras.isNotEmpty) { developer.log('Extras: $extras', name: name ?? 'App'); } } else { // Use Sentry in DEVELOPMENT for testing final attributes = {}; // Add extras as attributes if (extras != null) { extras.forEach((k, v) { attributes[k] = SentryLogAttribute.string(v.toString()); }); } // Add error and stackTrace as attributes if provided if (error != null) { attributes['error'] = SentryLogAttribute.string(error.toString()); } if (stackTrace != null) { attributes['stackTrace'] = SentryLogAttribute.string( stackTrace.toString(), ); } Sentry.logger.info( message, attributes: attributes.isNotEmpty ? attributes : null, ); // If debug mode is enabled in UAT, also print to console if (kDebugMode) { developer.log(message, name: name ?? 'App'); } } } //................................................................................................ /// Logs warning messages /// In Development: Prints to console with warning indicator /// In UAT/Production: Sends to Sentry as warning breadcrumb void warning( String message, { String? name, Object? error, StackTrace? stackTrace, Map? extras, }) { if (AppEnvironment.isDevelopment) { developer.log( '⚠️ WARNING: $message', name: name ?? 'App', error: error, stackTrace: stackTrace, ); if (extras != null && extras.isNotEmpty) { developer.log('Extras: $extras', name: name ?? 'App'); } } else { // Use Sentry for UAT and Production final attributes = {}; // Add extras as attributes if (extras != null) { extras.forEach((k, v) { attributes[k] = SentryLogAttribute.string(v.toString()); }); } // Add error and stackTrace as attributes if provided if (error != null) { attributes['error'] = SentryLogAttribute.string(error.toString()); } if (stackTrace != null) { attributes['stackTrace'] = SentryLogAttribute.string( stackTrace.toString(), ); } Sentry.logger.warn( message, attributes: attributes.isNotEmpty ? attributes : null, ); // If debug mode is enabled in UAT, also print to console if (kDebugMode) { developer.log('⚠️ WARNING: $message', name: name ?? 'App'); } } } //................................................................................................ /// Logs error messages /// In Development: Prints to console with error indicator /// In UAT/Production: Sends to Sentry as error event void error( String message, { String? name, Object? error, StackTrace? stackTrace, Map? extras, bool isFatal = false, }) { if (AppEnvironment.isDevelopment) { developer.log( '❌ ERROR: $message', name: name ?? 'App', error: error, stackTrace: stackTrace, level: 1000, // High level for errors ); if (extras != null && extras.isNotEmpty) { developer.log('Extras: $extras', name: name ?? 'App', level: 1000); } } else { // Use Sentry for UAT and Production final attributes = {}; // Add extras as attributes if (extras != null) { extras.forEach((k, v) { attributes[k] = SentryLogAttribute.string(v.toString()); }); } // Add error and stackTrace as attributes if provided if (error != null) { attributes['error'] = SentryLogAttribute.string(error.toString()); } if (stackTrace != null) { attributes['stackTrace'] = SentryLogAttribute.string( stackTrace.toString(), ); } // Add fatal flag as attribute if (isFatal) { attributes['fatal'] = SentryLogAttribute.string('true'); } Sentry.logger.error( message, attributes: attributes.isNotEmpty ? attributes : null, ); // If debug mode is enabled in UAT, also print to console if (kDebugMode) { developer.log( '❌ ERROR: $message', name: name ?? 'App', error: error, stackTrace: stackTrace, level: 1000, ); } } } //................................................................................................ /// Convenience method to log HTTP requests void logHttpRequest( String method, String url, { Map? headers, dynamic body, }) { log( 'HTTP $method: $url', name: 'HTTP', extras: { 'method': method, 'url': url, if (headers != null) 'headers': headers, if (body != null) 'body': body, }, ); } //................................................................................................ /// Convenience method to log HTTP responses void logHttpResponse( String method, String url, int statusCode, { dynamic body, }) { if (statusCode >= 200 && statusCode < 300) { log( 'HTTP $method Response: $url [$statusCode]', name: 'HTTP', extras: { 'method': method, 'url': url, 'statusCode': statusCode, if (body != null) 'body': body, }, ); } else { error( 'HTTP $method Error: $url [$statusCode]', name: 'HTTP', extras: { 'method': method, 'url': url, 'statusCode': statusCode, if (body != null) 'body': body, }, ); } } //................................................................................................ /// Logs navigation events void logNavigation(String route, {Map? arguments}) { log( 'Navigation to: $route', name: 'Navigation', extras: {'route': route, if (arguments != null) 'arguments': arguments}, ); } //................................................................................................ /// Logs user actions/events void logEvent(String eventName, {Map? properties}) { log( 'Event: $eventName', name: 'Event', extras: {'eventName': eventName, if (properties != null) ...properties}, ); } }