Table of Contents
Logging is an important part of every application, that supports the application life cycle. From the development to debugging, and adding new features, logging is used in all the ways possible. By analyzing the data in the logs, we came to know about the activities happening, resolve bugs much quicker, and detect problems early before they happen.
In this blog, we will talk about collecting, customizing logs for different environments and centralizing them with Node.js.
To put it in simple words, logs are a necessity to capture the stack traces, trace them back to specific user IDs, session IDs, Request endpoints and other types of activities that will help you efficiently monitor your application. Logging any exceptions thrown by our application helps you quickly debug the root cause of a problem in your code.
Morgan
I’m using Morgan, npm library for our discussion to describe the possibilities and configurations we can make to collect and customize the logs in Node.js.
Morgan is an HTTP request logger middleware for Node.js. It simplifies the process of logging requests for our application. It saves time for developers by generating automated logs based on the logger configuration. For example, Morgan can write requests in the Apache common format, split logs across outputs, and automatically rotate log files.
Morgan fits perfectly while Logging requests and/or responses in Express.js apps. This is because it is written as middleware. It’s also very easy to set up and use out of the box. Morgan can operate standalone, but commonly it’s used in combination with Winston. Winston can transport logs to an external location or query them when analyzing a problem.
Installation
npm i morgan
This command is used to install morgan within our application.
var morgan = require('morgan')
It is used to initialize the morgan library.
Formatting Options in Morgan
There are several formatting options available with Morgan for writing a log and are as follows,
- Using a predefined format string
- Using format string of predefined tokens
- Using a custom format function
Predefined format string
1. combined
Standard Apache combined log output;
:remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"
2. common
Standard Apache common log output;
:remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length]
3. dev
The response status is colored for development use. The: status token will be colored red for server error codes, yellow for client error codes, cyan for redirection codes, and uncolored for all other codes.
:method :url :status :response-time ms - :res[content-length]
4. short
In the ‘Short’ format, it will be shorter than the default, which will also include response time.
:remote-addr :remote-user :method :url HTTP/:http-version :status :res[content-length] - :response-time ms
5. tiny
The minimal output format.
:method :url :status :res[content-length] - :response-time ms
6. Using format string of predefined tokens
morgan(':method :url :status :res[content-length] - :response-time ms')
Writing logs to a file
An application log needs to be persisted so that we can analyze the log when an error occurred in our application. For this reason, we need to write the log into a file.
We can maintain a single log file for our application, to track all the actions/events happening within it. Here is a simple app that will log all requests in the Apache combined format to the file applogger.log.
var express = require('express'); var fs = require('fs'); var logger = require('morgan'); var path = require('path'); var app = express(); // create a write stream (in append mode) var accessLogStream = fs.createWriteStream(path.join(__dirname, 'applogger.log'), { flags: 'a' }); // setup the logger app.use(logger('combined', { stream: accessLogStream })) app.get('/', function (req, res){ … })
Logfile in a rotation manner
When the application usage increases and we need more tracking, we will not be able to maintain the log history in a single file. In this case, there are several options available like maintaining a logger file every day, compress the logger, now skip to a new file when the file size exceeds certain MB.
The following application will log all requests in the Apache combined format to one log file per day in the log/ directory using the rotating-file-stream module.
var express = require('express'); var fs = require('fs'); var morgan = require('morgan'); var path = require('path'); var rfs = require('rotating-file-stream'); var app = express(); var logDirectory = path.join(__dirname, 'log'); // ensure log directory exists fs.existsSync(logDirectory) || fs.mkdirSync(logDirectory); // create a rotating write stream var accessLogStream = rfs('applogger.log', { interval: '1d', // rotate daily path: logDirectory }); // setup the logger app.use(morgan('combined', { stream: accessLogStream })); app.get('/', function (req, res) { ... })
We can also enable combinations like, maintaining Log entry on request and one on a response, logging all requests to file, but errors to console, etc.,
Also Read
A Practical Guide To Avoid Memory Leaks In Node.js
Conclusion
Node.js provides simple logging through its run-time support using console.log, console.error and the third-party debug module. These options represent the least resistance for quick and dirty debugging. But, if you need more flexible logging, we have several NPM modules and based on our need and necessity we can choose one with logging levels, custom formats, support for multiple logging destinations and track our interactions with the application.
Like this post? Read more related Tech articles on our blog. Don’t forget to Subscribe to Agira’s exclusive newsletters.
Are you having an amazing app idea? Hunting for the right team of developers to make your dream a reality. Hire your developer now and expand your business across the horizons.