@zodyac/mono-logger
v2.0.0
Published
A simple topic-based logger with side effects
Downloads
8
Readme
Mono-logger
A simple logger module with topics and side-effects capabilities. It comes pretty useful when need to share common loggers across multiple modules or to nest loggers with different topics (e.g. function executors for debugging purposes).
Default logs format:
7/26/2024, 20:54:26 [DBG] root_topic:topic:subtopic hello, world
Changelog
Please see CHANGELOG for latest changes.
Installation
yarn add @zodyac/mono-logger
Or
npm i @zodyac/mono-logger
Topics
You can create a new child logger with a specific topic. This way you can filter logs by topic.
import { Logger } from '@zodyac/mono-logger';
const logger = new Logger();
const subLogger = logger.topic('sub-topic');
const deepSubLogger = subLogger.topic('deep-sub-topic');
deepSubLogger.log('hello, world');
// Output:
// 7/26/2024, 21:11:09 [DBG] sub-topic:deep-sub-topic hello, world
You can also access parent logger from a child logger.
import { Logger } from '@zodyac/mono-logger';
const logger = new Logger();
const subLogger = logger.topic('sub-topic');
const deepSubLogger = subLogger.topic('deep-sub-topic');
deepSubLogger._parent?.log('hello, world');
// Output:
// 7/26/2024, 21:11:09 [DBG] sub-topic hello, world
Configuration
Configuration can be set for the root logger or specific topic and its descendants. It means, that topic configuration will be inherited from it's parent. When you provide options for a new topic, it's going to override its parent configuration entirely.
Example:
const root_logger = new Logger("root", {
level: "info",
});
const sub_logger = root_logger.topic("leaf", {});
sub_logger.debug("I am still here!");
// Output:
// 7/26/2024, 21:11:09 [DBG] root:leaf I am still here!
You can configure the logger with:
level
: (e.g. debug) The minimum log level to be displayed.prefix
: (function) A prefix to be added to each log record before topics.date_format
: (function) The date formatter function to be used in logs.effect
: (function) A side-effect function to be called on each log record. It receives log level, list of topics and spread raw data array passed to logger.transform
: (function) A function to transform log records before being displayed.force_effect
: (boolean) If true, side-effects will be called even if log level is below the minimum level.
import { Logger } from '@zodyac/mono-logger';
const ex_logger = new Logger('example', {
level: 'debug',
prefix: () => 'my-app',
date_format: (date) => date.toISOString(),
effect: (level, topics, ...data) => console.log(level, topics, ...data),
transform: (m) => `yes, ${m}`,
force_effect: true,
});
ex_logger.log('hello', 'world');
// Output:
// 2024-07-26T18:47:01.978Z [DBG] my-app example yes, hello yes, world
// debug [ 'example' ] hello world
Side effects
You can assign any side effect you want to any topic and it's descendants (see Configuration). So each time you log something, the logger fires the effect
function with parameters:
level
- log leveltopics
(array, root to leaf)...raw
data you passed to logger
By default, when you log something below the minimum log level specified in Topic Configuration, effect
is not fired. You can force logger to fire it by passing force_effect
.
Inheritance
By default, every child logger will inherit configuration from it's parent, but if you'd like to customize a specific parameter, you can access parent's configuration as a readonly object:
const parent = logger.topic("parent", {
/* ... */
});
const child = root.topic("child", {
...parent._config,
effect: () => { /* do something else */ },
});
[!NOTE] You should not modify or override existing configuration. That is done on purpose to preserve verbosity and functional consistency.
MonoEffects and PolyEffects
MonoEffect
is a wrapper around your effect function with minimum log level check. Imagine this:
- Some module has a topic that is logged with
info
level; - There's a need to explicitly process all the
warn
,error
andfatal
logs that are generated by the module; - You create an effect and attach it to the topic logger;
In such situations, you can use MonoEffect
:
import { MonoEffect } from "@zodyac/mono-logger";
const handleWarnings = (lvl, topics, ...messages) => {
/*
* ...
* your custom warn, error and fatal handler
* ...
*/
console.warn("Warning has been recorded and saved");
};
const warnings_effect = new MonoEffect(handleWarnings, "warn");
const logger = root_logger.topic("target_module_name", {
level: "info",
effect: warnings_effect,
});
logger.warn("Example warning");
// Output:
// 2024-07-26T18:47:01.978Z [WRN] target_module_name Example warning
// Warning has been recorded and saved
PolyEffect
simply concatenates your effects and fires them one after another.
import { MonoEffect, PolyEffect } from "@zodyac/mono-logger";
const handleWarnings = (lvl, topics, ...messages) => {
/*
* ...
* your custom warn, error and fatal handler
* ...
*/
console.warn("Warning has been recorded and saved");
};
const handleFatal = (lvl, topics, ...messages) => {
/*
* ...
* your custom fatal handler
* ...
*/
console.error("x_x");
};
const warnings_effect = new MonoEffect(handleWarnings, "warn");
const fatal_effect = new MonoEffect(handleFatal, "fatal");
const poly_effect = new PolyEffect();
poly_effect.add(warnings_effect);
poly_effect.add(fatal_effect);
const logger = root_logger.topic("target_module_name", {
level: "info",
effect: poly_effect,
});
logger.warn("Example warning");
logger.fatal("Nope, I'm dead");
// Output:
// 2024-07-26T18:47:01.978Z [WRN] target_module_name Example warning
// Warning has been recorded and saved
// 2024-07-26T18:47:01.978Z [FTL] target_module_name Nope, I'm dead
// Warning has been recorded and saved
// x_x
You can use PolyEffect
to execute both parent and current effects. This will allow you to bypass the configuration inheritance limitation:
const poly_effect = new PolyEffect();
if (parent._config.effect) poly_effect.add(parent._config.effect);
poly_effect.add(() => { /* New effect */ });
const child = parent.topic("child", {
...parent._config,
effect: poly_effect,
});
Extensions
The list of known extensions and a guide on how to submit a new one can be found here.
Contributing
Contribution is always welcomed! These are several points of special interest:
- Writing tests (
Jest
); - Edge case exploration;
- Stability and performance improvements (KISS);
You are also welcome to extend and improve plugin ecosystem.
License
MIT