May 18, 2020


The problem

Keeping the interaction history with the application is quite important in every application if we don’t keep the logs the following occurs

  1. We are unable to track errors on production and their causes
  2. We are unable to monitor our system and be sure if some bugs or some functionality our users complain of is true.
  3. We are unable to obtain the transaction history with the application.


Add the following package winston

1npm i winston

we create a logger.js file and add the following

1import * as winston from 'winston';
2import 'winston-daily-rotate-file';
3import appRoot from 'app-root-path';
5const logger = winston.createLogger({
6 transports: [
7 new winston.transports.DailyRotateFile ({
8 filename: 'application-%DATE%.log',
9 dirname: `${appRoot}/logs/`,
10 level: 'info',
11 handleExceptions: true,
12 colorize: true,
13 json: false,
14 zippedArchive: true,
15 maxSize: '20m',
16 maxFiles: '14d'
17 })
18],exitOnError: false});
20export default logger;

For the above, we configured the logs to do the following

  • create a new instance of the Winston logger
1const logger = winston.createLogger({})
  • We configured new transport which is the medium we want to use to log our file called winston.transports.DailyRotateFile, our transport can also be of type console. we set our transport attributes to the following
1transports: [
2 new winston.transports.DailyRotateFile ({
3 filename: 'application-%DATE%.log',
4 dirname: `${appRoot}/logs/`,
5 level: 'info',
6 handleExceptions: true,
7 colorize: true,
8 json: false,
9 zippedArchive: true,
10 maxSize: '20m',
11 maxFiles: '14d'
12 })
  • log file will be created with name application-date.log
  • logs will be saved into a log folder in our root directory
  • Each log file will contain the logs of the application in a day
  • After a day the log file will be zipped to keep our growing file system in check
  • After 14days we’ll configure our logs to be archived.

For the winston logger we have various log level which are

1const levels = {
2 error: 0,
3 warn: 1,
4 info: 2,
5 verbose: 3,
6 debug: 4,
7 silly: 5

If any level is chosen the logger will log errors less than or equal to this level.

In the Entry of the application, we add the logger to the error middleware to enable all request and response and error to be logged in the application

1import logger from './logger.js';
3app.use((err, req, res, next) => {
4logger.error(`${err.status || 500} - ${err.message} - ${req.originalUrl} - ${req.method} - ${req.ip}`);
5res.status(500).send('server error, this will be resolved shortly!')

we can optionally add our logger to our controller to log errors we create a separate file called serverResponse

1import logger from './logger';
3* @name serverResponse
4* @param {Object} res express response object
5* @param {Number} code status code to return
6* @param {Object} data object with response details
7* @returns {JSON} JSON response with status and response information
9const serverResponse = (req, res, code, data) => {`${req.originalUrl} - ${req.method} - ${req.ip}
11- ${code} - ${JSON.stringify(data)}
13res.status(code).json({ });
16export default serverResponse;

This file will be used as a helper in our application to return our responses at the same time log the response to prevent repetitive code in the codebase.

Below is how it can be used in a typical controller

1import serverResponse from './serverResponse';
2class Auth {
4* @static
5* @param {JSON} req
6* @param {JSON} res
7* @memberof Auth
9static async login (req, res) {
10serverResponse(req, res, 200, {msg: 'login successful'});
11 }

Written by Adeyemi Adekorede
You can follow him on Twitter