✏️ A mixin for Dart classes that brings contextual logging functionality to your class.
Print messages like this w/o any effort.
10:03:00 [I] MyController : Initializing ...
10:03:01 [I] MyController : Initialized!
🌐 Is built on top of the
logger
package.
We all know log messages. They are printed to the console, to the files or whatever. Dart provides us with methods for logging like:
print('A message');
debugPrint('Another message');
Good enough to debug. But when you actually need to investigate users' journey, it is not. You'll need context. The context here answers the question who has printed the message?
.
Adding context could be done like this:
print('My Controller : A message');
debugPrint('My Controller : Another message');
... and it will work. Though to write the context every time is pretty boring. This is what contextual_logging
solves.
Attach the mixin it to your class that you want to use for logging:
class MyController with ContextualLogging
And now go for it!
class MyController with ContextualLogging {
Future<void> init() async {
log.i('Initializing ...'); // <-- Access logging via the log field
await fetchData();
log.i('Initialized!');
}
}
You will see this in the console:
10:03:00 [I] MyController : Initializing ...
10:03:01 [I] MyController : Initialized!
By default, a logger is created for every object that has a ContextualLogging
mixin attached to it. Once you attach the mixin, you'll be able to configure the logger for this object.
logContext
property is what Contextual Logger adds to the log message in front of the main message. By default it has a value of this.toString()
. Override it to whatever you want:
class MyController with ContextualLogging {
@override
String get logContext => 'SomeOtherContext`;
void test() {
log.i('Test'); // 19:12:00 [I] SomeOtherContext : Test
}
}
If you want to use a custom logger, feel free to override the customLogger
property:
class MyController with ContextualLogging {
@override
Logger get customLogger => Logger(/* Configure it in whatever way you want! */);
void test() {
log.i('Test'); // Still access it via the `log` property!
}
}
If you want to reconfigure loggers for all the object at once, do this before your app starts:
// ContextualLogger mixin uses this defaultLogger by default to get a logger for the object it was attached to.
ContextualLoggingConfig.defaultLogger = (forObject) => MyBeautifulLogger(forObject);
Once you do it, every ContextualLogger
mixin will create loggers like this.
💡 A printer is what formats your messages.
When setting the ContextualLoggingConfig.defaultLogger
property, you can create a logger and provide any printer you want. Or you can use the default printer used by ContextualLogger
, the ContextualLogPrinter
. This printer is what makes the messages look like this:
12:01:00 [I] SomeOtherContext : Test
Instead of this:
Test
There are plenty of properties you can change:
Property | Type | Description | Default |
---|---|---|---|
forObject | Object | The object for which the logger was created. Use a string if you want to have it as a prefix. |
this |
timeFormat | DateFormat | Format of the current timestamp | HH:mm:ss |
timeInUtc | bool | Whether the current timestamp must be in UTC | false |
printTime | bool | Whether to print the timestamp | true |
logLevelLabel | Function | Log level prefix for messages | [I], [W] etc |
So imagine you've overridden the printer like this:
ContextualLoggingConfig.defaultLogger = (forObject) {
return Logger(
printer: ContextualLogPrinter(
forObject: forObject,
printTime: false, // Note!
),
);
};
// This will make your messages look like this:
[I] MyController : A message
Log level lebel is what allows you to distinguish the level of a message. The logger
package allows you to use these levels:
Level | Function | Default | Emoji |
---|---|---|---|
Verbose | log.v |
[V] | None |
Debug | log.d |
[D] | 🐛 |
Info | log.i |
[I] | 💡 |
Warning | log.w |
[W] | |
Error | log.e |
[E] | ⛔️ |
Wtf | log.wtf |
[WTF] | 🗿 |
Nothing | log.log(Level.nothing, ...) |
None | None |
Override the logLevelLabel
property to make your own prefixes!
ContextualLoggingConfig.defaultLogger = (forObject) {
return Logger(
printer: ContextualLogPrinter(
forObject: forObject,
logLevelLabel: (level) {
/* Return a prefix for the given level! */
},
),
);
// Or do this to enable emojis level!
ContextualLoggingConfig.defaultLogger = (forObject) {
return Logger(
printer: ContextualLogPrinter(
forObject: forObject,
logLevelLabel: ContextualLogPrinter.emojiLevelLabel,
),
);