Closed geekflyer closed 4 years ago
Hi Christian,
I appreciate your request for such a comparison. Even though I understand your wish, I have to admit that I am not a fan of such an overview. On the one hand, they usually seem biased, so that the selected features are by pure accident exactly the ones that are supported by your own package (all of them are always checked). On the other hand, I don't think it's appropriate, especially in the open-source community to judge someone else's work. Every author of every open-source library invests his (free) time and therefore every library has a right to exist, as long as it helps others. I don't feel being in the position to judge somebody else's work.
I think my job as the author of this library is to maintain it and list all its features in a compact way and leave you to compare and decide which one to use.
I hope you understand my thoughts.
One question though:
What exactly is your use-case of having a child logger?
tslog
supports multiple loggers with different configurations and it's rather easy to achieve having a minLevel
for all of them by simply putting this setting into a variable or an ENV.
Is there something I'm missing? Thanks!
Hi @terehov,
I respect your thought on this, altho personally I have a bit of a different opinion. I think it's quite possible to give an honest comparison to other libraries and mention the main motivation why a new library was built and what limitations one ran into, but also what the new library can't do (yet). Here's a good example of such a comparison: https://foalts.gitbook.io/docs/topic-guides/comparison-with-other-frameworks. This generally just helps people find the library with the right tradeoff for their needs as there's a rarely one single best library for all use-cases out there. I also understand that naturally all such comparisons by a library author have a level of bias (and some have a lot), but I (hope) most people have a healthy awareness of that bias and take that into consideration when reading a comparison from a library author.
Anyways, that aside :) - coming to your other question: The typical case of child logger is to pass around some contextual attribute without repeating oneselves, in some cases many levels deep down the call stack.
For example let's say you have some code that processes a message from a message queue and you want to attach that messageId to every log line. Here's some code to demonstrate this:
type Message { id: string, type: string, payload: any };
function processMessage(message: Message) {
const logger = rootLogger.child({messageId: messageId, messageType: message.type});
logger.info('Going to process message');
try {
await doExpensiveStuff(message.payload, logger);
logger.info('Finished processing message');
} catch (e) {
logger.error('Failed to process message', {err});
}
}
in this example each of the log lines would have messageId
and messageType
as json attributes, even though I just typed it out in the beginning when the child logger was created. Furthermore even the log lines produced by the operations inside doExpensiveStuff
would have those attributes as well. Lastly doExpensiveStuff could internally create a a child logger from the child logger and add another attribute that gets added to the context. In general this is how child loggers work in pino,winston and roarrr.
roarr even allows passing attributes/context to child functions without explicitly passing the logger using roarr.adopt
, which leverages JS domains
(will be replaced with async_hooks).
As for creating multiple loggers with different configurations:
I actually would like to have all logger instances have a single parent (rootLogger called in my example above) and inherit some config from that which I can set / change at runtime.
The particular use-case I have in mind is having an application in production whose log level is set to info
but by flipping a switch somewhere (i.e. change a param in config file that is being continuously watched or use something like https://cloud.google.com/deployment-manager/runtime-configurator ) one could set the log level to debug temporarily, which is useful to debug issues in production during an incident without requiring a restart of the application.
Changing the log level dynamically at runtime is something that is supported by winston (see the "You may also dynamically change the log level of a transport:" section of https://github.com/winstonjs/winston) for example by setting transports.console.level = 'debug'
and in this case would automatically propagate to all loggers using this transport incl. their respective child loggers.
Hope that helps to provide some context :)
Thanks, @geekflyer!
In our projects, we have a helper LoggerFactory
but I see your point that it makes sense to have this inside. I'm a bit busy these days, but I'll give it some thoughts and try to come up with a solution soon 👍
Hey @geekflyer, thanks for hanging in.
I have just pre-released a version that tackles this issue 2.3.0-0
.
https://www.npmjs.com/package/tslog/v/2.3.0-0
I am still working on some more tests and docs, but it would be awesome if you could give it a spin and tell me how you like it.
New features:
prefix
: You can now pass attributes that will be prefixed to every log messagegetChildLogger()
create a new child logger, that inherits all settings from its parent. All settings can be overwritten.setSettings()
: New settings will also be propagated to all child loggers.npm i tslog@next
Example:
/* Child Logger Example */
const mainLogger: Logger = new Logger({
name: "MainLogger",
printLogMessageInNewLine: true,
prefix: ["main"],
});
mainLogger.info("MainLogger initiated");
const childLogger1 = mainLogger.getChildLogger({
name: "ChildLogger1",
prefix: ["child1"],
});
childLogger1.info("ChildLogger1 initiated");
const childLogger1_1 = childLogger1.getChildLogger({
name: "ChildLogger1-1",
prefix: ["child1-1"],
});
childLogger1_1.info("ChildLogger1-1 initiated");
childLogger1_1.silly("ChildLogger1-1 silly 1");
childLogger1_1.silly("ChildLogger1-1 silly 2");
childLogger1_1.silly("ChildLogger1-1 silly 3");
mainLogger.setSettings({ minLevel: "debug" });
childLogger1_1.silly("ChildLogger1-1 silly 4");
childLogger1_1.silly("ChildLogger1-1 silly 5");
mainLogger.setSettings({
minLevel: "silly",
prefix: ["mainRenamed"],
});
childLogger1_1.silly("ChildLogger1-1 silly 6");
childLogger1.setSettings({ prefix: ["child1Renamed"] });
childLogger1_1.debug("ChildLogger1-1 debug finish");
Output:
Every author of every open-source library invests his (free) time and therefore every library has a right to exist, as long as it helps others
Clarifying key differences or your motivation to start this project shouldn't conflict with that belief.
A subjective, but respectful comparison to prior arts goes a very long way in helping others pick the right tool for the right job.
+1 especially when making claims that this library is ⚡ Small footprint, blazing performance (native V8 integration)
I'd love to understand what this means when it comes to logging and if it is still blazing performance
when compared to other (optimized) logging libraries. I can't seem to find any performance testing anywhere. Has anyone set up a test?
Features are nice and all but at the end of the day I like to understand how a logging library performs first and then decide if those extra features are worth the performance degradation (if any).
Definitely not trying to argue this library shouldn't exist, it sure looks pretty and feature rich just trying to figure out which library to use ¯_(ツ)_/¯
Hi there,
I came across tslog in search of a good logging library and it looks promising! I'm currently mostly using pino but having some issues with it's API and other things.
I was wondering if you could give a quick summary on how this logging library compares to X, what you did differently, why and what's the overall philosophy of it? I'm sort of tasked with defining some best practices wrt to logging and observability at my company.
When I say X, I mostly mean:
Some features that I'm looking for usually:
Appreciate your thoughts!