Setting up a custom logger for node express typescript server

In the last tutorial, we learnt how to setup typescript to a node-express app. Let’s move further, and setup a custom logger for our node-express-typescript app, so that whenever we want to log something in our terminal, we have pretty colored and formatted outputs. We don’t want console.log’s anymore in our application code. So let’s do it and create our custom logger, which also saves logs to a file with all the requests and errors.

For various environments, we might need different levels of logging in our app. To help with this we will use winston that provides levels for our logging. morgan is pretty handy when it comes to logging the request and response headers. We gonna be using chalk, because we want colored messages !

Sounds cool ! let’s get started

Add the following dependencies,

<<em>code</em>>$ npm install --save winston morgan @<em>types</em>/<em>morgan</em></<em>code</em>>
JavaScript

Once added, let’s configure our logger:

In lib/logger.ts, add the following :

import * as winston from 'winston';

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

const colors = {
    error: "red",
    warn: "yellow",
    info: "green",
    verbose: "gray",
    debug: "blue",
    silly: "grey"
}

const level = () => {
    const env = process.env.NODE_ENV || 'development'
    const isDevelopment = env === 'development'
    return isDevelopment ? 'debug': 'warn'
}

winston.addColors(colors);

const winstonFormat = winston.format.combine(
    winston.format.colorize({
        all: true
    }),
    winston.format.label({
        label: '[LOGGER]'
    }),
    winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss:ms'}),
    winston.format.align(),
    winston.format.printf(
        (<em>info</em>) => `${info.timestamp} ${info.level}: ${info.message}`,
    )
)

const winstonLogger =  winston.createLogger({
    level: level(),
    levels,
    format: winstonFormat,
    transports: [
        <strong>new</strong> winston.transports.Console(),
        <strong>new</strong> winston.transports.File({
            filename: 'logs/error.log',
            level: 'error',
        }),
        <strong>new</strong> winston.transports.File({ filename: 'logs/all.log' }),
    ],
});

export default winstonLogger;
JavaScript

Also, we might need to use our winstonLogger to write logs to a file (to save logs)

What we can do is we can use the winstonLogger and use its output as stream and pass it to
our morgan middleware.

In config/morganMiddleware.ts , add the following :

import * as morgan from 'morgan';
import { isDevelopment } from '../env';
import { logger } from '../lib';

const loggerStream: <em>morgan</em>.<em>StreamOptions</em> = {
    write: (<em>message</em>) =>
        logger.http(message.substring(0, message.lastIndexOf('\n')))
}

const morganMiddleware = morgan(
    ':method :url :status :res[content-length]- :response-time ms - API Server',
    { stream: loggerStream, skip: () => !isDevelopment},
)

export default morganMiddleware;
JavaScript

Also, lets use some colors for our console logs, we will use chalk, update the above file like this:

import chalk from 'chalk';
import * as morgan from 'morgan';
import { isDevelopment } from '../env';
import { logger } from '../lib';

const loggerStream: <em>morgan</em>.<em>StreamOptions</em> = {
    write: (<em>message</em>) =>
        logger.http(message.substring(0, message.lastIndexOf('\n')))
}

const morganMiddleware = morgan(
    chalk.yellow(':method :url :status :res[content-length]- :response-time ms'),
    { stream: loggerStream, skip: () => !isDevelopment},
)

export default morganMiddleware;
JavaScript

Now finally, the logging should happen like this :

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *