Logging
FLEX provides a FlexLogger
feature that offers structured, configurable, and colorful logging for Flutter applications. The logging system supports multiple log levels, custom output handlers, and scoped loggers for better organization and debugging.
Overview
Section titled “Overview”The FLEX logging system consists of:
- FlexLogger: Core singleton logger with configurable output
- ScopedLogger: Component-specific loggers with preset sources
- FlexLoggerConfig: Configuration for log levels, formatting, and output
- LoggingFeature: FLEX feature integration for easy setup
Configuration
Section titled “Configuration”Basic Setup
Section titled “Basic Setup”Configure logging in your main.dart
:
await FlexCore.initialize([ LoggingFeature( config: const FlexLoggerConfig( minLevel: kDebugMode ? LogLevel.debug : LogLevel.info, showEmojis: true, showTimestamp: true, showSource: true, useShortName: true, enableColors: true, ), ), // Other features...]);
Log Levels
Section titled “Log Levels”FLEX supports six log levels with different visual indicators:
enum LogLevel { trace, // ⬜ Most verbose - detailed execution flow debug, // 🟦 Debug information for development info, // 🟩 General information about app state warn, // 🟨 Warning messages for potential issues error, // 🟥 Error conditions that need attention fatal, // ☠️ Critical errors that may crash the app}
Configuration Options
Section titled “Configuration Options”const FlexLoggerConfig( // Minimum log level to display minLevel: LogLevel.info,
// Visual formatting showTimestamp: true, // Include timestamps: [14:30:25.123] showSource: true, // Show component/source names showEmojis: true, // Include emoji indicators useShortName: false, // Use TRC/DBG instead of TRACE/DEBUG
// Console output enableConsole: true, // Print to console/debug output enableColors: true, // Use ANSI colors in console enableSourcePadding: true, // Pad source names for alignment
// Error handling includeStackTraces: true, // Include stack traces for errors
// Custom output customLogger: myCustomLogger, // Send logs to external systems)
Basic Usage
Section titled “Basic Usage”Getting a Logger
Section titled “Getting a Logger”// Get the global logger instancefinal logger = FlexCore.logger;
// Get a scoped logger for a specific componentfinal logger = FlexCore.getLogger('ProductService');
Logging Messages
Section titled “Logging Messages”class ProductService { final logger = FlexCore.getLogger('ProductService');
Future<List<Product>> fetchProducts() async { logger.debug('Starting product fetch');
try { logger.info('Fetching products from API'); final products = await _apiCall();
logger.info('Successfully fetched ${products.length} products'); return products;
} catch (error, stackTrace) { logger.error( 'Failed to fetch products', error: error, stackTrace: stackTrace, ); rethrow; } }}
All Log Levels
Section titled “All Log Levels”class ExampleService { final logger = FlexCore.getLogger('ExampleService');
void demonstrateLogLevels() { // Trace - Most verbose, execution flow logger.trace('Entering method demonstrateLogLevels()');
// Debug - Development information logger.debug('Processing user input: ${userInput}');
// Info - General application flow logger.info('User successfully logged in');
// Warn - Potential issues logger.warn('API response time is higher than expected (2.5s)');
// Error - Error conditions logger.error('Failed to save user preferences', error: exception);
// Fatal - Critical system errors logger.fatal('Database connection lost', error: error, stackTrace: stack); }}
Scoped Loggers
Section titled “Scoped Loggers”Creating Scoped Loggers
Section titled “Creating Scoped Loggers”Scoped loggers automatically include a source identifier:
class AuthBloc extends Bloc<AuthEvent, AuthState> { final logger = FlexCore.getLogger('AuthBloc');
Future<void> login(String email, String password) async { logger.info('Login attempt for user: $email');
try { final result = await _authService.login(email, password); logger.info('Login successful for user: $email'); emit(AuthStateAuthenticated(result));
} catch (error) { logger.error('Login failed for user: $email', error: error); emit(const AuthStateError('Login failed')); } }}
Widget Logging
Section titled “Widget Logging”class ProductCardWidget extends StatefulWidget { @override _ProductCardWidgetState createState() => _ProductCardWidgetState();}
class _ProductCardWidgetState extends State<ProductCardWidget> { final logger = FlexCore.getLogger('ProductCard');
@override void initState() { super.initState(); logger.debug('ProductCard initialized'); }
void _onAddToCart() { logger.info('Add to cart button pressed for product: ${widget.product.id}');
try { // Add to cart logic logger.info('Product added to cart successfully'); } catch (error) { logger.error('Failed to add product to cart', error: error); } }}
Advanced Configuration
Section titled “Advanced Configuration”Environment-Based Configuration
Section titled “Environment-Based Configuration”FlexLoggerConfig getLoggerConfig() { if (kDebugMode) { // Development configuration return const FlexLoggerConfig( minLevel: LogLevel.trace, showEmojis: true, showTimestamp: true, enableColors: true, includeStackTraces: true, ); } else if (kProfileMode) { // Profile/staging configuration return const FlexLoggerConfig( minLevel: LogLevel.info, showEmojis: false, showTimestamp: true, enableColors: false, includeStackTraces: false, ); } else { // Production configuration return const FlexLoggerConfig( minLevel: LogLevel.warn, showEmojis: false, showTimestamp: false, enableConsole: false, customLogger: productionLogger, ); }}
Custom Log Output
Section titled “Custom Log Output”void productionLogger( String message, LogLevel level, String source, Object? error, StackTrace? stackTrace,) { // Send to analytics service AnalyticsService.logEvent('app_log', { 'message': message, 'level': level.name, 'source': source, 'timestamp': DateTime.now().toIso8601String(), });
// Send errors to crash reporting if (level == LogLevel.error || level == LogLevel.fatal) { CrashReporting.recordError(error, stackTrace, { 'message': message, 'source': source, }); }}
Best Practices
Section titled “Best Practices”Structured Logging
Section titled “Structured Logging”class OrderService { final logger = FlexCore.getLogger('OrderService');
Future<Order> createOrder(OrderRequest request) async { final orderId = generateOrderId();
logger.info('Creating order: $orderId'); logger.debug('Order details: items=${request.items.length}, total=${request.total}');
try { final order = await _processOrder(request);
logger.info('Order created successfully: $orderId, amount=${order.total}'); return order;
} catch (error, stackTrace) { logger.error( 'Order creation failed: $orderId', error: error, stackTrace: stackTrace, ); rethrow; } }}
Context-Rich Logging
Section titled “Context-Rich Logging”class CartBloc extends Bloc<CartEvent, CartState> { final logger = FlexCore.getLogger('CartBloc');
void _onAddItem(AddCartItem event, Emitter<CartState> emit) { final userId = state.user?.id ?? 'anonymous'; final itemId = event.product.id;
logger.info('Adding item to cart: user=$userId, item=$itemId, qty=${event.quantity}');
try { final updatedCart = state.cart.addItem(event.product, event.quantity);
logger.info('Item added successfully: cart_size=${updatedCart.items.length}, total=${updatedCart.total}'); emit(state.copyWith(cart: updatedCart));
} catch (error) { logger.error('Failed to add item to cart: user=$userId, item=$itemId', error: error); emit(state.copyWith(error: 'Failed to add item to cart')); } }}
Performance Monitoring
Section titled “Performance Monitoring”class ApiService { final logger = FlexCore.getLogger('ApiService');
Future<T> _timedRequest<T>( String endpoint, Future<T> Function() request, ) async { final stopwatch = Stopwatch()..start(); logger.trace('Starting request to $endpoint');
try { final result = await request(); stopwatch.stop();
final duration = stopwatch.elapsedMilliseconds; if (duration > 2000) { logger.warn('Slow API response: $endpoint took ${duration}ms'); } else { logger.debug('API request completed: $endpoint (${duration}ms)'); }
return result;
} catch (error) { stopwatch.stop(); logger.error('API request failed: $endpoint (${stopwatch.elapsedMilliseconds}ms)', error: error); rethrow; } }}
Error Context
Section titled “Error Context”class PaymentService { final logger = FlexCore.getLogger('PaymentService');
Future<PaymentResult> processPayment(PaymentRequest request) async { final correlationId = uuid.v4();
logger.info('Processing payment: id=$correlationId, amount=${request.amount}, method=${request.method}');
try { final result = await _chargeCard(request);
logger.info('Payment successful: id=$correlationId, transaction=${result.transactionId}'); return result;
} on PaymentDeclinedException catch (error) { logger.warn('Payment declined: id=$correlationId, reason=${error.reason}'); rethrow;
} on NetworkException catch (error, stackTrace) { logger.error('Payment network error: id=$correlationId', error: error, stackTrace: stackTrace); rethrow;
} catch (error, stackTrace) { logger.fatal('Unexpected payment error: id=$correlationId', error: error, stackTrace: stackTrace); rethrow; } }}
Shorthand Methods
Section titled “Shorthand Methods”For quick logging, use the shorthand methods:
class QuickLoggingExample { final logger = FlexCore.getLogger('QuickExample');
void demonstrateShorthand() { logger.t('Trace message'); // trace() logger.d('Debug message'); // debug() logger.i('Info message'); // info() logger.w('Warning message'); // warn() logger.e('Error message'); // error() logger.f('Fatal message'); // fatal() }}
Log Output Examples
Section titled “Log Output Examples”Development Mode Output
Section titled “Development Mode Output”🟦 [14:30:25.123] DEBUG: User authentication started🟩 [14:30:25.456] INFO: Token validation successful🟨 [14:30:25.789] WARN: Session expires in 5 minutes🟥 [14:30:26.012] ERROR: Failed to refresh token☠️ [14:30:26.345] FATAL: Authentication service unavailable
Production Mode Output
Section titled “Production Mode Output”[2023-12-25T14:30:25.123Z] WARN: [AuthService] Session expires in 5 minutes[2023-12-25T14:30:26.012Z] ERROR: [AuthService] Failed to refresh token[2023-12-25T14:30:26.345Z] FATAL: [AuthService] Authentication service unavailable
Integration Examples
Section titled “Integration Examples”With Error Reporting
Section titled “With Error Reporting”void setupProductionLogging() { FlexLogger.configure(FlexLoggerConfig( minLevel: LogLevel.info, customLogger: (message, level, source, error, stackTrace) { // Send to Firebase Crashlytics if (level == LogLevel.error || level == LogLevel.fatal) { FirebaseCrashlytics.instance.recordError( error ?? message, stackTrace, information: [ DiagnosticsProperty('source', source), DiagnosticsProperty('message', message), DiagnosticsProperty('level', level.name), ], ); }
// Send to analytics FirebaseAnalytics.instance.logEvent( name: 'app_log', parameters: { 'level': level.name, 'source': source, 'message': message.length > 100 ? message.substring(0, 100) : message, }, ); }, ));}
The FLEX logging system provides a powerful foundation for debugging, monitoring, and maintaining Flutter applications with comprehensive logging capabilities that scale from development to production.