Better logs for ExpressJS using Winston and Morgan with Typescript

A step-by-step guide on how to configure an ExpressJS application with Winston and Morgan loggers using Typescript

Andrea Vassallo
Level Up Coding

--

Photo by Nubelson Fernandes on Unsplash

A great log system is one of the easiest ways to check your application behavior and it’s our first weapon to look into bugs

If you are starting or have already started an ExpressJS application, you may have wondered, how can I create a great and well-organized log system?

The problem is that a lot of applications don’t have a comprehensive log system, or even worse, they use simple console.log everywhere.

In this article, you’ll find out how to configure logs using Winston and Morgan.

TL;DR;

Here you can find the fully configured project (Use the branch calledcomplete )

I didn’t add unit tests in this article but the code below is fully tested. You can find all the tests inside the repository above.

Do you need a great template to start your ExpressJS GraphQL APIs? Use mine: https://github.com/vassalloandrea/express-template

Let’s start

First of all, we need an ExpressJS application. You can clone this repository.

git clone https://github.com/vassalloandrea/medium-morgan-winston-example.git

Start the server

The project was created using a from-scratch basic configuration. Start the server using this command:

cd medium-morgan-winston-example
npm install
npm run dev

Install Winston

Winston is a useful library that is needed to configure and customize the application logs accessing a lot of helpful features.

To use the plainconsole.log without a third-party library, we need to write a lot of code and reinvent the wheel understanding all the edge cases caught by Winston in these years.

Here there are the main features that we should implement inside our project:

  • Differentiate log levels: error, warn, info, HTTP, debug
  • Differentiate colors adding one to each log level
  • Show or hide different log levels based on the application ENV; e.g., we won’t show all the logs when the application runs in production.
  • Adding a timestamp to each log line
  • Save logs inside files
npm install winston

Configure Winston

In the lines below, there is a simple configuration of our logger. Copy and paste them inside your project. You can use this path: src/lib/logger.ts or something similar.

I’ll explain every single row later.

Now you have the ability to use the Logger function anywhere inside your application importing it.

Go to the index.ts file where the ExpressJS server is defined and replace all the console.log with the custom Logger methods.

See the result starting the server and navigating thought the logger endpoint:

As you can see, the logger shows logs using different colors based on their severity, and another important feature is that all these logs are also printed out inside the all.log and error.log files under the logs directory.

Learn more about the configuration

The configuration file is straightforward. Check the comments inside the file below.

Take stock of the situation

Now we have the ability to instrument the application code adding logs based on the complexity of the feature.

With Winston, you can also change the log severity at the runtime using an ENV variable.

Since ExpressJS is made to handle requests, we should add a request logger that automatically logs every request information. The goal should be reached using a library that can be easily integrated with the Winston configuration.

Install Morgan

Morgan is a NodeJS middleware that is needed to customize request logs.

The integration with Winston it’s very simple. Do you remember the http severity level that we added to the Winston configuration? Well, it was made to be used only from the Morgan middleware.

npm install morgan @types/morgan

Configure Morgan

In the lines below, there is a simple configuration of the Morgan middleware. Copy and paste them inside your project. You can use this path: src/config/morganMiddleware.ts or something similar.

Read the comments to understand or extend the configuration below.

Add this middleware to the ExpressJS server inside the index.ts file:

import morganMiddleware from './config/morganMiddleware'...
...
const PORT = 3000;app.use(morganMiddleware)app.get("/logger", (_, res) => {...

Start the server and make the request visiting the logger endpoint:

Here are other examples of request logs:

Enjoy the configuration

That’s all! I hope that this configuration will help you all to instrument your code, finding hidden bugs more easily. 🐛

Did you like this article? Let me know with a clap and a comment 🙏

Do you need help with your ExpressJS app? Hire me

Deepening with the GraphQL Morgan configuration

This section is just a deepening for projects that use GraphQL.

GraphQL has just one route by default, so we need to change the Morgan configuration to make sense.

--

--

I’m a full-stack developer with 6 years of experience creating GraphQL/REST APIs, building React/Vue SPA, and managing great Rails e-commerce using Solidus.