Node.js Logging Done the Right Way
I’m going to talk about logging in nodejs in this article. Logging is the most important part of your application but to make it work proper in scalable applications like microservice architectures becomes difficult, as you would want to know the logs you see are coming from where!
I will show you how I make logging in nodejs streamlined and avoid logging at multiple places unnecessarily.
Table of Contents
- Implementing Logging in Nodejs
- Implement remote log stream
A proper logging structure will make it easy for you and coming developers to put logs in your application. I’m using express framework in this article, but you can implement the same in any framework of your choice.
We need a logging library to print logs, Bunyan is a good option out there. Remember you can always replace your logger library easily inside our logger service and that’s the benefit of implementing this logger service.
You can follow along the article and go through the code on github
We will make a modular logger that can be imported anywhere in your project without worrying about changing the logger at anytime and not affecting your whole project. If you ever need to change level or you want to use a new logging library, you can do so in this file.
If you have scaffolded your app using express generator, you will have an error handler created for you, else you want to create one shown below inside your app.js file. This middleware accepts first parameter as error and is called whenever you make a next(error) call.
If you are a newbie in express, there is an example of next() coming in this article, keep going.
You can import the logger service in all your project modules and log easily the same way it’s used inside app.js error handler. But now you will do that rarely because of this error handler which logs every error you pass inside next as next(error) from your routes. Lets put this together and see how it works.
This is one route registered with app.js, and is attached at api endpoint /api/user. If you make a mongoose query or call a function which returns a promise or accepts a callback function, you can always do next(error) inside catch of promise or callback function if error is not null. This avoid you writing an additional logging statement and also makes it easy to send a response to user with proper error message, all because of error handler that we wrote just above.
Above code snippet passes the error to error handler, hence it does not require to import the logger service and the error automatically gets logged inside the error handler we wrote above. You can still import logger service to log info and other level, take a look at the below code snippet.
Here we imported the logger service and used it to log an info about the requested users id.
You can use the logger this way anywhere in your project and log anything. The best part is again replace the logger library inside logger service, change the log level and any settings and you are good to go with new library without any extra changes. We are done with logging setup here but now lets see how we can see those logs on a remote website by just enhancing our logger service, after all who wants to see logs in a log file anymore!
If you haven’t been using any remote logging service before, you should now. This allows viewing your logs at nice place by just login into your account and lets you analyze the logs, you can do filtering and all kind of stuff easily. We will integrate logentries in our logger service to see and analyze logs at logentries. There are other choices for logging service you can choose according to your needs. I have used logentries in a few of my projects and it does really a good job.
We need a bunyan transport to send logs to logentries, The below one is very light implementation over tcp, Install bunyan-transport
Now lets require this module to make our logger service send logs to logentries. Make changes to the logger.js file as shown below, we only changed our logger service and everything just works as it is, but now you will see logs at logentries.com instead of the console.
Bunyan prints a lot more information than you might need sometimes, you can configure which key values to be sent to logentries inside bunyan transport. You can read more about it here at bunyan-transport
Till here its all fine, but you may be thinking to use this only in prod environment and not in development mode. You can sure do that, and I guess you already have your own way working with different environments, but still here’s a snippet to put all together.
I always keep a separate group of modules to read and validate environment variables and export as config to consume in my project. I will directly use the environment variables here to show you the working of logger. Based on type of environment we create a logger and export that from logger service, which includes log level as well.
So, that’s how I make a streamlined logger in my nodejs projects, please share what tools you use in your projects and any suggestion on how this can be improved, and thanks for reading this article.