cover

Effective and Simple Logging in NestJS Using Pino Logger

4 Minutes

What is logging?

Logging is information in Programming to trace some behaviour inside our software.

In computing, logging is the act of keeping a log of events that occur in a computer system, such as problems, errors or just information on current operations (Wikipedia)

Why this is important?, I remember when I got feedback from user about their bug, identify the bug and find “what is wrong” is tedious when we do not know what point should we check.

Logging is usefull to find the error, behaviour, and other thing at spesific time. We can see clear information what our app do and what the data that logged in.

There is some restriction data that SHOULD NOT inserted in log data, like user’s raw password.

What make log usefull? There is some level of work at logging.

  1. Collection, How log collected?, what data should we log?, we should create a program to handle the log, this program could be a function, class, separate program or anything. Other program should able call this program easily and make integration seamlessly. Repeated behaviour like server request and response, change page, user id should logged automatically.

  2. Transport, you should transport the log data in a file or other log as a service. Store this data will make we able to identify the problem as soon as possible.

Installation Pino

We will not explore more about this, but we will write how to logging in nestjs. Nestjs already written how to do logger in their documentation. They recommend to use Winston as their log library, but I use Pino because they have Pino-Nestjs module for easy integration.

How to use pino nestjs? Let say you have setup nestjs in your computer. First, install some package

$ npm install nestjs-pino pino-http pino-pretty
  • nestjs-pino Nestjs module to use pino

  • pino-http HTTP Logger for Nestjs

  • pino-pretty Pino log terminal color

# I use this version when write this blog
    "pino-http": "^10.1.0",
    "nestjs-pino": "^4.1.0",
    "pino-pretty": "^11.2.1",

Configuration Pino and Nestjs

You can find detail nestjs pino integration at Pino Nestjs module library documentation, Add this to your app.module.ts

@Module({
  imports: [ 
   LoggerModule.forRoot({
      pinoHttp: {
        name: 'Nestjs',
        level: process.env.NODE_ENV === 'production' ? 'info' : 'debug',
        transport: {
          targets: [
            {
              target: 'pino-pretty',
              level: 'debug',
            },
          ],
        },
      },
    }),
  ]
})
export class AppModule { }

Add this to your main.ts

import { Logger, LoggerErrorInterceptor } from 'nestjs-pino';
import { ValidationPipe, Logger as LoggerNest } from '@nestjs/common';
async function bootstrap(){
      const app = await NestFactory.create(AppModule);
      // add this --v
      app.useLogger(app.get(Logger));    

      await app.listen(process.env.PORT || 4000);
      // Example use the logger
      const logger = new LoggerNest('Bootstrap');
      logger.log(`Application is running on ${await app.getUrl()}`)
}

How to use logger in your service

How to use logger in your service

// NestJS standard built-in logger.
// Logs will be produced by pino internally
import { Logger } from '@nestjs/common';

export class MyService {
  private readonly logger = new Logger(MyService.name);
  foo() {
    // All logger methods have args format the same as pino, but pino methods
    // `trace` and `info` are mapped to `verbose` and `log` to satisfy
    // `LoggerService` interface of NestJS:
    this.logger.verbose({ foo: 'bar' }, 'baz %s', 'qux');
    this.logger.debug('foo %s %o', 'bar', { baz: 'qux' });
    this.logger.log('foo');
  }
}

Better Log configuration

Usually I do not need all information in nesjts terminal, I ignore headers response and request. I also export all log into a file for easy integration and history

LoggerModule.forRoot({
      pinoHttp: {
        name: 'Nestjs',
        level: process.env.NODE_ENV === 'production' ? 'info' : 'debug',
        transport: {
          targets: [
            {
              target: 'pino-pretty',
              level: 'debug',
              options: {
                colorize: true,
                ignore: 'req.headers,res.headers',
              },
            },
            {
              target: 'pino/file',
              level: 'debug',
              options: {
                destination: './logs/app.log',
                mkdir: true,
              },
            },
            {
              target: 'pino/file',
              level: 'error',
              options: {
                destination: './logs/app-error.log',
                mkdir: true,
              },
            },
          ],
        },
      },
    })

Please read carefully the code to understand it.

What function of these code?

  • I remove request headers and response headers

  • I store all log into ./logs/app.log

  • I store all log error into ./logs/app-error.log

Add logs directory into your .gitignore to ignore it from you git history.

Conclusion

Log is usefull to trace problem and behaviour of program. I use pino as library logger and it have pino nestjs module for easy integration. Thank you for your visit in this article, follow me at instagram @rio_chndr, github RioChndr, and see other article at blog.riochndr.com

comments powered by Disqus