26 Logging Intro
I’ve build a Flutter app and use debugPrint() to log message in all my code. Now, the app is growing fast and I’d like to use logging package to manage app logging.
Please teach me about the logging package. How it works and the benefits of using it.
Great to hear you’re expanding your Flutter knowledge! The logging package is an excellent choice for managing app logs as your Flutter app grows. Let me walk you through it with your background in mind.
26.1 What is the logging package?
The logging package is Dart’s official hierarchical logging library. Think of it like Python’s logging module - it provides structured, configurable logging with different severity levels and the ability to route logs to different outputs.
26.2 Key Benefits over debugPrint()
Structured Logging: - Hierarchical loggers (like myapp.network, myapp.database) - Severity levels (SEVERE, WARNING, INFO, CONFIG, FINE, etc.) - Rich log records with timestamps, logger names, and metadata
Production-Ready: - Can be completely disabled in release builds - Route logs to files, network endpoints, or crash reporting services - No performance impact when disabled
Flexible Configuration: - Control log levels per logger - Multiple output handlers - Custom formatting
26.3 Basic Usage
Here’s how you’d convert from debugPrint():
import 'dart:developer' as developer;
import 'package:logging/logging.dart';
// Create loggers (usually as static final)
final _logger = Logger('MyApp.HomePage');
final _networkLogger = Logger('MyApp.Network');
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
void initState() {
super.initState();
// Before: debugPrint('HomePage initialized');
_logger.info('HomePage initialized');
_fetchData();
}
Future<void> _fetchData() async {
try {
// Before: debugPrint('Fetching user data...');
_networkLogger.info('Fetching user data...');
final response = await api.getUserData();
// Before: debugPrint('Data fetched successfully');
_networkLogger.info('Data fetched successfully', response.data);
} catch (e) {
// Before: debugPrint('Error fetching data: $e');
_networkLogger.severe('Failed to fetch user data', e);
}
}
}26.4 Logger Hierarchy
Loggers follow a hierarchical naming convention:
MyApp <- Root logger
├── MyApp.Network <- Network operations
├── MyApp.Database <- Database operations
├── MyApp.HomePage <- Specific page
└── MyApp.UserService <- Business logic
Child loggers inherit settings from parents, similar to CSS cascade.
26.5 Configuration Setup
Set this up early in your main() function:
import 'package:logging/logging.dart';
import 'dart:developer' as developer;
void main() {
_setupLogging();
runApp(MyApp());
}
void _setupLogging() {
// Set minimum log level
Logger.root.level = kDebugMode ? Level.ALL : Level.WARNING;
// Listen to all log records
Logger.root.onRecord.listen((record) {
// Format log message
final message = '${record.level.name}: ${record.time}: '
'${record.loggerName}: ${record.message}';
if (kDebugMode) {
// In debug mode, print to console
developer.log(
record.message,
time: record.time,
level: record.level.value,
name: record.loggerName,
error: record.error,
stackTrace: record.stackTrace,
);
}
// In production, you might send to crash reporting
// crashlytics.log(message);
});
}26.6 Log Levels (from highest to lowest severity)
SEVERE(1000): Serious failuresWARNING(900): Potential problems
INFO(800): General informationCONFIG(700): Configuration messagesFINE(500): Tracing informationFINER(400): Fairly detailed tracingFINEST(300): Highly detailed tracing
26.7 Practical Migration Strategy
Start with main areas:
final _authLogger = Logger('MyApp.Auth'); final _apiLogger = Logger('MyApp.API'); final _uiLogger = Logger('MyApp.UI');Replace
debugPrint()gradually:// Before debugPrint('User logged in: ${user.email}'); // After _authLogger.info('User logged in', {'email': user.email});Use appropriate levels:
_logger.fine('Button tapped'); // Debug info _logger.info('Data loaded'); // General info _logger.warning('Slow response'); // Potential issue _logger.severe('Login failed', error); // Critical error
This approach gives you professional-grade logging that scales with your app. The hierarchical structure will help you debug specific areas, and you can easily adjust verbosity for different parts of your application.