onufitness_mobile/lib/services/logger_service.dart
2026-01-13 11:36:24 +05:30

266 lines
7.4 KiB
Dart

// 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<String, dynamic>? 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 = <String, SentryLogAttribute>{};
// 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<String, dynamic>? 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 = <String, SentryLogAttribute>{};
// 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<String, dynamic>? 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 = <String, SentryLogAttribute>{};
// 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<String, dynamic>? 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<String, dynamic>? arguments}) {
log(
'Navigation to: $route',
name: 'Navigation',
extras: {'route': route, if (arguments != null) 'arguments': arguments},
);
}
//................................................................................................
/// Logs user actions/events
void logEvent(String eventName, {Map<String, dynamic>? properties}) {
log(
'Event: $eventName',
name: 'Event',
extras: {'eventName': eventName, if (properties != null) ...properties},
);
}
}