Streamline Your Flutter App Debugging with Custom Loggers
In any robust application, effective logging is essential for tracing issues and understanding application behavior. In this blog, I’ll guide you through creating a custom logger in Flutter using the logger
package and the get_it
service locator for easy access throughout your app.
Step 1: Adding Dependencies
First, let’s add the necessary dependencies to your pubspec.yaml
file:
dependencies:
flutter:
sdk: flutter
logger: ^1.4.0
get_it: ^7.2.0
Step 2: Creating the Custom Logger
We will create a CustomLogger
class to manage logging. This logger will capture log messages, errors, and stack traces and store them in a buffer for later retrieval.
Create a new file named custom_logger.dart
:
import 'package:logger/logger.dart';
class CustomLogger {
static final CustomLogger _instance = CustomLogger._internal();
factory CustomLogger() {
return _instance;
}
CustomLogger._internal() {
_logger = Logger(
printer: PrettyPrinter(
methodCount: 2,
errorMethodCount: 5,
lineLength: 120,
colors: true,
printEmojis: true,
printTime: true,
),
);
}
late final Logger _logger;
final StringBuffer _logBuffer = StringBuffer();
void _logToBuffer(String level, String message, [dynamic error, StackTrace? stackTrace]) {
_logBuffer.writeln('${DateTime.now()}: $level - $message');
if (error != null) {
_logBuffer.writeln('Error: $error');
}
if (stackTrace != null) {
_logBuffer.writeln('StackTrace: $stackTrace');
}
}
void debug(String message, [dynamic error, StackTrace? stackTrace]) {
_logToBuffer('DEBUG', message, error, stackTrace);
_logger.d(message, error, stackTrace);
}
void info(String message, [dynamic error, StackTrace? stackTrace]) {
_logToBuffer('INFO', message, error, stackTrace);
_logger.i(message, error, stackTrace);
}
void warning(String message, [dynamic error, StackTrace? stackTrace]) {
_logToBuffer('WARNING', message, error, stackTrace);
_logger.w(message, error, stackTrace);
}
void error(String message, [dynamic error, StackTrace? stackTrace]) {
_logToBuffer('ERROR', message, error, stackTrace);
_logger.e(message, error, stackTrace);
}
void verbose(String message, [dynamic error, StackTrace? stackTrace]) {
_logToBuffer('VERBOSE', message, error, stackTrace);
_logger.v(message, error, stackTrace);
}
void wtf(String message, [dynamic error, StackTrace? stackTrace]) {
_logToBuffer('WTF', message, error, stackTrace);
_logger.wtf(message, error, stackTrace);
}
String getLogs() {
return _logBuffer.toString();
}
}
Step 3: Setting Up GetIt
Next, we set up get_it
to register and provide our CustomLogger
singleton. Create a new file named locator.dart
:
import 'package:get_it/get_it.dart';
import 'custom_logger.dart';
final GetIt getIt = GetIt.instance;
void setupLocator() {
getIt.registerSingleton<CustomLogger>(CustomLogger());
}
CustomLogger get appLog => getIt<CustomLogger>();
Step 4: Initializing the Service Locator
We need to initialize the service locator before running the app. Update your main.dart
file:
import 'package:flutter/material.dart';
import 'locator.dart';
void main() {
setupLocator();
appLog.info("App started");
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Custom Logger Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
try {
throw Exception("An example exception");
} catch (e, stackTrace) {
appLog.debug('Debug message', e, stackTrace);
appLog.info('Info message', e, stackTrace);
appLog.warning('Warning message', e, stackTrace);
appLog.error('Error message', e, stackTrace);
appLog.verbose('Verbose message', e, stackTrace);
appLog.wtf('WTF message', e, stackTrace);
}
},
child: Text('Log Messages'),
),
ElevatedButton(
onPressed: () {
final logs = appLog.getLogs();
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Logs'),
content: SingleChildScrollView(
child: Text(logs),
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text('Close'),
),
],
);
},
);
},
child: Text('Show Logs'),
),
],
),
),
),
);
}
}
Final Thoughts
By following these steps, you can set up a powerful custom logging system in your Flutter app. This approach provides a flexible and centralized way to manage logs, making it easier to debug and trace issues in your application. Happy logging!