Giter VIP home page Giter VIP logo

nestjs-pino's Introduction

NestJS-Pino logo

NestJS-Pino

npm Travis (.org) Coverage Status Snyk Vulnerabilities for npm package David Dependabot Supported platforms: Express & Fastify

✨✨✨ Platform agnostic logger for NestJS based on Pino with REQUEST CONTEXT IN EVERY LOG ✨✨✨

Example

Import module:

import { LoggerModule } from 'nestjs-pino';

@Module({
  imports: [LoggerModule.forRoot()],
  controllers: [AppController],
  providers: [MyService]
})
class MyModule {}

In controller:

import { Logger } from 'nestjs-pino';

@Controller()
export class AppController {
  constructor(
    private readonly myService: MyService,
    private readonly logger: Logger
  ) {}

  @Get()
  getHello(): string {
    this.logger.log("getHello()", AppController.name);
    return `Hello ${this.myService.getWorld()}`;
  }
}

In service:

import { Logger } from 'nestjs-pino';

@Injectable()
export class MyService {
  constructor(private readonly logger: Logger) {}

  getWorld(...params: any[]) {
    this.logger.log("getWorld(%o)", MyService.name, params);
    return "World!";
  }
}

Output:

// Logs by Nest itself, when set `app.useLogger(app.get(Logger))`
{"level":30,"time":1570470154387,"pid":17383,"hostname":"my-host","context":"RoutesResolver","msg":"AppController {/}: true","v":1}
{"level":30,"time":1570470154391,"pid":17383,"hostname":"my-host","context":"RouterExplorer","msg":"Mapped {/, GET} route true","v":1}
{"level":30,"time":1570470154405,"pid":17383,"hostname":"my-host","context":"NestApplication","msg":"Nest application successfully started true","v":1}

// Logs by injected Logger methods in Services/Controllers
// Every log has it's request data
{"level":30,"time":1570470161805,"pid":17383,"hostname":"my-host","req":{"id":1,"method":"GET","url":"/","headers":{...},"remoteAddress":"::1","remotePort":53957},"context":"AppController","msg":"getHello()","v":1}
{"level":30,"time":1570470161805,"pid":17383,"hostname":"my-host","req":{"id":1,"method":"GET","url":"/","headers":{...},"remoteAddress":"::1","remotePort":53957},"context":"MyService","msg":"getWorld([])","v":1}

// Automatic logs of every request/response
{"level":30,"time":1570470161819,"pid":17383,"hostname":"my-host","req":{"id":1,"method":"GET","url":"/","headers":{...},"remoteAddress":"::1","remotePort":53957},"res":{"statusCode":304,"headers":{...}},"responseTime":15,"msg":"request completed","v":1}

Comparison with others

There are other Nestjs loggers. The key purposes of this one are:

  • to be compatible with built in LoggerService
  • to log with JSON (thanks to pino - super fast logger) (why JSON?)
  • to log every request/response automatically (thanks to pino-http)
  • to bind request data to the logs automatically from any service on any application layer without passing request context
Logger Nest App logger Logger service Autobind request data to logs
nest-morgan - - -
nest-winston + + -
nestjs-pino-logger + + -
nestjs-pino + + +

Install

npm i nestjs-pino

Register module

Default params

Just import LoggerModule to your module:

import { LoggerModule } from 'nestjs-pino';

@Module({
  imports: [LoggerModule.forRoot()],
  ...
})
class MyModule {}

Synchronous configuration

LoggerModule.forRoot has the same API as pino-http:

import { LoggerModule } from 'nestjs-pino';

@Module({
  imports: [
    LoggerModule.forRoot(
      {
        name: 'add some name to every JSON line',
        level: process.env.NODE_ENV !== 'production' ? 'debug' : 'info',
        prettyPrint: process.env.NODE_ENV !== 'production',
        useLevelLabels: true,
        // and all the others...
      },
      someWritableStream
    )
  ],
  ...
})
class MyModule {}

Asynchronous configuration

With LoggerModule.forRootAsync you can for example import your ConfigModule and inject ConfigService to use it in useFactory method.

useFactory should return result typeof arguments of pino-http or null or Promise of it, example:

import { LoggerModule } from 'nestjs-pino';

@Injectable()
class ConfigService {
  public readonly level = "debug";
}

@Module({
  providers: [ConfigService],
  exports: [ConfigService]
})
class ConfigModule {}

@Module({
  imports: [
    LoggerModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: async (config: ConfigService) => {
        await somePromise();
        return { level: config.level };
      }
    })
  ],
  ...
})
class TestModule {}

Or without ConfigModule you can just pass ConfigService to providers:

import { LoggerModule } from 'nestjs-pino';

@Injectable()
class ConfigService {
  public readonly level = "debug";
  public readonly stream = stream;
}

@Module({
  imports: [
    LoggerModule.forRootAsync({
      providers: [ConfigService],
      inject: [ConfigService],
      useFactory: (config: ConfigService) => {
        return [{ level: config.level }, config.stream];
      }
    })
  ],
  controllers: [TestController]
})
class TestModule {}

Extreme mode

If you want to enable extreme mode you should read pino extreme mode docs first.

If you are ok with that, so you can configure module like this:

import * as pino from 'pino';
import { LoggerModule } from 'nestjs-pino';

const dest = pino.extreme();
const logger = pino(dest);

@Module({
  imports: [LoggerModule.forRoot({ logger })],
  ...
})
class MyModule {}

Also you can read more about Log loss prevention.

Usage as Logger service

Logger implements standard NestJS LoggerService interface. So if you are familiar with built in NestJS logger you are good to go.

// my.service.ts
import { Logger } from 'nestjs-pino';

@Injectable()
export class MyService {
  constructor(private readonly logger: Logger) {}

  getWorld(...params: any[]) {
    this.logger.log("getWorld(%o)", MyService.name, params);
    return "World!";
  }
}

Usage as NestJS app logger

According to official docs, loggers with Dependency injection should be set via following construction:

import { Logger } from 'nestjs-pino';

const app = await NestFactory.create(MyModule, { logger: false });
app.useLogger(app.get(Logger));

FAQ

Q: How does it work?

A: It use pino-http under hood, so every request has it's own child-logger, and with help of async_hooks Logger can get it while calling own methods. So your logs can be groupped by req.id.

Q: Why use async_hooks instead of REQUEST scope?

A: REQUEST scope can have perfomance issues depending on your app. TL;DR: using it will cause to instantiating every class, that injects Logger, as a result it will slow down your app.

Q: I'm using old nodejs version, will it work for me?

A: Please read this.

Q: What about pino built in methods/levels?

A: Pino built in methods are not compatible to NestJS built in LoggerService methods, so decision is to map pino methods to LoggerService methods to save Logger API:

pino LoggerService
trace verbose
debug debug
info log
warn warn
error error

nestjs-pino's People

Contributors

chrisgco avatar dependabot-preview[bot] avatar iamolegga avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.