Generic Logger for Flutter
A generic, customizable logging library that works seamlessly across Flutter, Dart VM, and web builds—without initializing or depending on any third-party logging packages internally. Instead of enforcing a specific logging backend, users inject their own preferred logging implementation, making this a truly framework-agnostic and highly flexible solution for Flutter applications.
Features
- 🚀 Plug-and-play adapters (Console, File) with clear blueprints for HTTP/cloud adapters.
- 🛡️ Built-in sanitization with tag-specific overrides to keep sensitive data safe.
- 🧰 Fluent context builder and scoped loggers for ergonomic instrumentation.
- ⚙️ Configurable error handling, severity thresholds, and repository lifecycle management.
- 🧪 Unit-tested core plus CI workflow and documentation tooling.
Installation
Add the package to your pubspec.yaml:
dependencies:
generic_logger:
path: ../generic_logger/flutter_generic_logger
(Replace the path above with the appropriate location once published to pub.dev.)
Quick Start
import 'package:generic_logger/generic_logger.dart';
Future<void> bootstrapLogging() async {
final logger = Logger(
config: LoggerRepositoryConfig(
severity: LogLevel.debug,
),
);
await logger.registerAdapter(
'console',
ConsoleLoggerAdapter(),
config: const ConsoleAdapterConfig(
enabled: true,
colorize: true,
),
);
logger.info('Generic Logger ready 🚀');
}
Scoped logging
final authLogger = ScopedLogger.tag('Auth');
authLogger.debug(
'Attempting login',
options: LogContextBuilder()
.metadata({'strategy': 'password'})
.build(),
);
authLogger.error(
'Login failed',
error: Exception('Invalid credentials'),
options: const EnhancedLogOptions(
data: {'email': 'hidden@example.com'},
),
);
File logging
final fileAdapter = FileLoggerAdapter();
await fileAdapter.initialize(
FileAdapterConfig(
enabled: true,
directory: '/tmp',
formats: {FileLogFormat.text, FileLogFormat.json},
),
);
await logger.registerAdapter('file', fileAdapter);
Sanitization
Sanitization runs automatically when sanitizationEnabled is true (default).
You can supply custom sanitizers per tag or per log call.
class PaymentSanitizer extends Sanitizer {
@override
Object? sanitize(Object? data) {
if (data is Map<String, Object?>) {
return {
...data,
'cardNumber': '[REDACTED]',
};
}
return data;
}
}
final repository = LoggerRepository.getInstance();
repository.registerSanitizer('Payment', PaymentSanitizer());
Skip sanitization for a specific call:
logger.debug(
'Diagnostics payload',
options: const EnhancedLogOptions(
data: {'raw': 'large-object'},
skipSanitization: true,
),
);
Error handling
Provide a custom error handler to capture adapter failures:
final repository = LoggerRepository.getInstance(
config: LoggerRepositoryConfig(
onAdapterError: (error, stack) {
// Forward to Crashlytics, Sentry, etc.
},
),
);
Project scripts
flutter test— run unit testsflutter analyze— lint with recommended rulestool/generate_docs.sh— regenerate API documentationnpm run flutter:version:patch|minor|major— bump versions from the repository root (--releaseadds branch/tag automation)npm run flutter:release:create flutter-vX.Y.Z— re-create GitHub release notes if needed
Roadmap
- Streaming adapters (HTTP, Firebase, Firehose)
- Structured tracing integration
- Devtools log viewer widget
License
MIT © Thomas Samoul