Transports
Transports are the key to Crispin. While Crispin itself acts as a "Singleton", transports are instantiated and given to Crispin as such
Crispin().addTransport(...)
.
Please note that no Transports come bundled with pub add crispin
Channels (under consideration)#
While we currently don't support channels, we are thinking of supporting channel specific transports (e.g. Crispin('user_stuff').addTransport(//Transport configured for User logs)
).
Transport Foundational Understanding#
All transports must extend CrispinTransport
abstract class. This class allows you to easily understand the available methods and parameters for each method, while controlling exactly what happens.
Enabling Log Levels#
isEnabled
is not required it can provide granular control of a given transport. For instance, instead of using an environment key to conditionally add a given transport, you can decide what levels are available via environment key or whatever you want. That said, we do recommend controlling the enabling of levels via parameters to a given transport.
import 'package:crispin/crispin.dart';
import 'package:logger_crispin_transport/logger_crispin_transport.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
void main() {
Crispin().addTransport(LoggerCrispinTransport(LoggerCrispinTransportOptions(level: dotenv.get('LOGGER_LEVEL', 'warn'))));
}
Another way is to simply not implement the method
@override
Future<void> silly(String message, {Object? meta}) async {
// You can just fully ignore implementing a method but doing so means you're aware that you didn't implement it.
}
Project Specific Transports#
If you'd like to make your own transport specific to a given project simply extend the CrispinTransport
abstract as shown in following:
import 'package:crispin/crispin.dart';
class PrintTransport extends CrispinTransport {
PrintTransport(this.highestLevel);
final String highestLevel;
bool isEnabled(int level) {
final isEnabled = CrispinLoggerLevel.isValidName(highestLevel);
if (isEnabled && highestLevel.isNotEmpty) {
return level <= CrispinLoggerLevel.getFromName(highestLevel);
}
return false;
}
///
@override
Future<void> info(String message, {Object? meta}) async {
if (isEnabled(CrispinLoggerLevel.info)) {
print('INFO: $message');
if (meta != null) {
print(' meta: $meta');
}
print('');
}
}
///
@override
Future<void> warn(String message, {Object? meta}) async {
if (isEnabled(CrispinLoggerLevel.warn)) {
print('WARN: $message');
if (meta != null) {
print(' meta: $meta');
}
print('');
}
}
///
@override
Future<void> debug(String message, {Object? meta}) async {
if (isEnabled(CrispinLoggerLevel.debug)) {
print('DEBUG: $message');
if (meta != null) {
print(' DEBUG meta: $meta');
}
print('');
}
}
///
@override
Future<void> silly(String message, {Object? meta}) async {
// You can just fully ignore implementing a method but doing so means you're aware that you didn't implement it.
}
///
@override
Future<void> error(String message, {Object? error, StackTrace? stackTrace}) async {
if (isEnabled(CrispinLoggerLevel.error)) {
print('ERROR: $message');
if (error != null) {
print(' error: ${error.toString()}');
}
if (stackTrace != null) {
print(' stackTrace: ${stackTrace.toString()}');
}
print('');
}
}
}
void main() {
Crispin().addTransport(PrintTransport('warn'));
Crispin().warn('this is a warning');
Crispin().info('Not enabled');
try {
throw Exception('Error for example');
} catch (error, stackTrace) {
Crispin().error('Handling Error', error: error, stackTrace: stackTrace);
}
}
Testing#
When using Crispin
in tests, there are a few helpful methods for clearing and resetting transports.
Two common ones are removeAllTransports
and removeTransportByType
.
Official Transports#
- LoggerCrispinTransport
pub add logger_crispin_transport
- SentryCrispinTransport
pub add sentry_crispin_transport