Creating a custom logger in Node JS using Winston
Tags: node, webdev, javascript, winston
Published: 2024-04-11 14:02:57

Hello fellow developers,

I am excited to share with you how you can use winston to develop a custom logger for your node js application. This is beginner friendly and anyone can follow.

Let's get started:
Create an empty directory:

```
mkdir node-logger
cd node-logger
code .
```
Open the terminal inside the VS code 
Initialize package.json:
```
npm init -y
```
Install express, dotenv, winston and nodemon:

```
npm install --save-dev express dotenv winston nodemon
```
create the `index.js` file:

```
touch index.js
```
After creating `index.js` go to `package.json` and add the `start script` inside `scripts`:

```
"scripts": {
    "start": "nodemon index.js",
  },
```

In `index.js` lets set up the basic server configuration using Express.

```
const express = require("express");
const dotenv = require("dotenv");
dotenv.config();

const PORT = process.env.PORT || 8000;
const app = express();

app.listen(PORT, ()=>{
  console.log(`listening on http://localhost:${PORT}`)
});
```
Let us now create the `.env` file:
`touch .env`
Now add your environment variables inside your `.env` file:

```
PORT=8000
NODE_ENV=development
```

With that done, in the terminal inside your VS code, create a folder `utils` and inside `utils` create a file called `logger.js`:

```
mkdir utils
cd utils
touch logger.js
```
In `logger.js`, lets write the logging logic. First let us import winston and configure dotenv: 

```
const winston = require("winston");
const dotenv = require("dotenv");
dotenv.config();
```

Then we will define our security levels:

```
const levels = {
  error: 0,
  warn: 1,
  info: 2,
  http: 3,
  debug: 4,

}

const level = () => {
  const isDevelopment = process.env.NODE_ENV || "development";
  return isDevelopment ? "debug" : "warn";
};
```
We will define different colors for each level and tell winston to use those colors:

```
const colors = {
  error: "red",
  warn: "yellow",
  info: "green",
  http: "magenta",
  debug: "white",
};

winston.addColors(colors);
```
After that, select the aspect of our logging process to customize the log format:

```
const format = winston.format.combine(
  winston.format.timestamp({
    format: "YYYY-MM-DDTHH:mm:ss",
  }),

  winston.format.colorize({ all: true }),

  winston.format.printf(
    (info) => `${info.timestamp} ${info.level}: ${info.message}`
  )
);
```
Let's define the transports that the logger must use for printing out messages:

```
const transports = [
  // Allow the user to console/print the message
  new winston.transports.Console(),
  // Allow to print all error level messages inside the all.log file
  new winston.transports.File({
    filename: "logs/error.log",
    level: "error",
  }),

  // Allow to print all messages inside the all.log file
  new winston.transports.File({
    filename: "logs/all.log",
  }),
];
```

Configure the transports that the logger needs to employ for displaying messages:

```
const Logger = winston.createLogger({
  level: level(),
  levels: levels,
  format: format,
  transports: transports,
  exitOnError: false,
});

module.exports = Logger;
```
In your `index.js` import `logger` from `logger.js`:

```
const Logger = require("./utils/logger");
```
replace `console.log` with `Logger.http`
Finally, start the server:

```
npm start
```