Logging is undoubtedly one of the most important parts of our application. Now, console is a very powerful tool, yes, but what if we wanted to log not only to console but also to a file?
We could try to write a function logToFile and call it right after console.log. This, however, is not the most DRY (don't repeat yourself) way to go about it.
What we actually want to achieve is to have a single logger, in which, by calling - for example - logger.info, the message is automatically logged into our console, saved into two files, and whatever else we might need at the time.
Libraries like Winston, which provide logging in our applications, are very good at what they do, so we don't really need to reinvent the wheel. Still, I believe that implementing such a library ourselves often provides a lot of insight into how they work. Also, we may want to do a few things differently and add a feature or two.
Go ahead and clone the repository and let's get started by having a look at what we want to achieve:
createLogger
Here is the interface for the createLogger's config:
Inside format.text we use the node-emoji library, which lets us get the Unicode of emojis. They then can be rendered correctly in our terminal, our file, or anywhere else.
So, Here is a message :heart:, becomes Here is a message ❤️.
It adds a little flavor to our logs and, for me, simply looks good.
Place in the code where logger.info was called...
Whenever we log something we may forget where the log was located - I know it is not a problem to find it - but still, it is interesting how one would go about finding it without searching manually.
If you think about it, we have this one way of revealing all the called functions just before the one we are in right now - it's what we call a stack. We can gain access to the stack by throwing an error.
Here is how this is going to work:
- We throw an error inside our function
- We catch the error immediately and check its stack
- We split the stack by new line and have as a result an array with each line of the stack being a separate element. Now we filter the array to get only those lines starting with 'at' since we are only interested in locations
- We either get the location at the index provided to the function or at the first one (default), which means any function that was called before getLocation(). You can look at the locations like: [getLocation, functionThatCalledGetLocation (the default one), functionThatCalledFunctionThatCalledGetLocation, ...].
https://logrocket.com/signup/