A flexible and memory-efficient logger for Dart/Flutter applications, providing structured, color-coded output with support for complex data types and truncation.
- Structured Output: Pretty-prints Maps and Lists in a JSON-like format for easy readability.
- Color-Coded Levels: Differentiates between INFO, WARNING, and ERROR logs using distinct colors (in terminals supporting ANSI codes).
- Handles Complex Data: Logs primitives (String, num, bool, null), Maps, Lists, and supports
dio
'sRequestOptions
andFormData
out-of-the-box. - Memory Efficient: Designed to reduce intermediate string creation, especially important when logging large data structures.
- Truncation: Automatically truncates deep or large collections (Maps/Lists) to prevent excessive memory usage and overly long logs.
- Configurable maximum depth and maximum collection entries.
- Can be enabled/disabled globally or per log call.
- Configuration: Set global defaults for truncation behavior, depth/entry limits, and the underlying log handler (
dart:developer
by default). - Clean Formatting: Uses clear single-line headers/footers to delineate log blocks.
- Static Utility: Includes
DynamicLogger.formatData
to format data structures into strings without logging. - Easy Access: Simple static methods (
DynamicLogger.log
,DynamicLogger.configure
) for convenient use.
Add dynamic_logger
as a dependency in your pubspec.yaml
file:
dependencies:
dynamic_logger: ^0.2.1 # Replace with the latest version
dio: ^5.0.0 # Add dio if you need to log RequestOptions/FormData
Then run dart pub get or flutter pub get.
Import the package and use the static log method.
import 'package:dynamic_logger/dynamic_logger.dart';
void main() {
// Log a simple message (defaults to INFO)
DynamicLogger.log('User logged in successfully.');
// Log with a specific level and tag
DynamicLogger.log(
'Configuration file not found, using defaults.',
level: LogLevel.WARNING,
tag: 'ConfigLoader',
);
// Log an error with a tag
DynamicLogger.log(
'Failed to connect to database.',
level: LogLevel.ERROR,
tag: 'Database',
// stackTrace: stackTrace, // Optionally include stack trace
);
// Log a Map
final userData = {'id': 123, 'name': 'Alice', 'isActive': true, 'prefs': {} };
DynamicLogger.log(userData, tag: 'UserData');
// Log a List
final items = ['apple', 10, true, null, {'nested': 'value'}, []];
DynamicLogger.log(items, tag: 'ItemList');
}
You can set global defaults for the logger's behavior. This is useful for setting up truncation project-wide.
import 'package:dynamic_logger/dynamic_logger.dart';
import 'dart:developer' as developer; // Example: using dart:developer
void setupLogger({bool isProduction = false}) { // Example: pass build flag
DynamicLogger.configure(
// Enable truncation by default for all logs
truncate: true,
// Set default max depth for nested structures
maxDepth: 5,
// Set default max entries shown for Maps/Lists
maxCollectionEntries: 20,
// Globally enable or disable logging (defaults to true)
enable: !isProduction, // Disable logs in production builds <-- MODIFIED Example
// Optionally override the default log handler (e.g., for custom output)
// logHandler: (message, {level, name, ...}) {
// print("[$name - Level $level]: $message");
// }
);
print("Logger configured: Enabled=${!isProduction}, Truncation=true"); // MODIFIED Example
}
void main() {
bool kReleaseMode = const bool.fromEnvironment('dart.vm.product');
setupLogger(isProduction: kReleaseMode);
// Subsequent logs will use the configured defaults unless overridden
// DynamicLogger.log(someVeryLargeMap); // Will be truncated by default (if enabled)
DynamicLogger.log("This log might be disabled depending on the build mode.");
}
Even if you have global defaults, you can override truncation settings for specific log calls.
// Assume default truncation is enabled via configure()
// final largeJsonData = ...; // Your large data structure
// Log a specific large object WITHOUT truncation for debugging
DynamicLogger.log(
largeJsonData,
tag: 'FullDebugData',
truncate: false, // Disable truncation for this call only
);
// Log another large object with stricter limits than the default
DynamicLogger.log(
largeJsonData, // Using the same data for example
tag: 'BriefOverview',
truncate: true, // Ensure truncation is on for this call
maxDepth: 2,
maxCollectionEntries: 5,
);
Use formatData
to get the formatted string representation of an object without actually logging it. It respects the configured truncation defaults unless overridden.
final data = {'a': 1, 'b': [1, 2, 3], 'c': {'d': 'hello'} };
// Format using default truncation settings
String formattedString = DynamicLogger.formatData(data);
print("Formatted Data:\n$formattedString");
// Format with specific truncation for this call
String truncatedString = DynamicLogger.formatData(
data,
truncate: true,
maxDepth: 1,
maxCollectionEntries: 1,
);
print("\nTruncated Formatted Data:\n$truncatedString");
*** (Note: Colors are represented conceptually. Actual output depends on terminal support.) ***
MIT License. See the LICENSE file for details.