Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to inject winston's logger instance with NestJS

I'm using NestJS 7.0.7 and Winston 3.2.1 (with nest-winston 1.3.3).

I'm trying to integrate Winston into NestJS, but so far, I'm unable to inject a logger instance (to actually log anything) into any controller/service.

Since I would like to use Winston across the application AND during bootstrapping, I'm using the approach as the main Nest logger:

// main.ts
import { NestFactory } from "@nestjs/core";
import { WinstonModule } from "nest-winston";
import { format, transports } from "winston";
import { AppModule } from "./app.module";

async function bootstrap(): Promise<void> {
  const app = await NestFactory.create(AppModule, {
    logger: WinstonModule.createLogger({
      exitOnError: false,
      format: format.combine(format.colorize(), format.timestamp(), format.printf(msg => {
        return `${msg.timestamp} [${msg.level}] - ${msg.message}`;
      })),
      transports: [new transports.Console({ level: "debug" })], // alert > error > warning > notice > info > debug
    }),
  });
  app.use(helmet());
  await app.listen(process.env.PORT || 3_000);
}

bootstrap().then(() => {
  // ...
});

I'm not doing anything in regard to the logging in app.module.ts:

// app.module.ts
import { SomeController } from "@controller/some.controller";
import { Module } from "@nestjs/common";
import { SomeService } from "@service/some.service";

@Module({
  controllers: [SomeController],
  imports: [],
  providers: [SomeService],
})
export class AppModule {
  // ...
}
// some.controller.ts
import { Controller, Get, Inject, Param, ParseUUIDPipe, Post } from "@nestjs/common";
import { SomeService } from "@service/some.service";
import { WINSTON_MODULE_PROVIDER } from "nest-winston";
import { Logger } from "winston";

@Controller("/api/some-path")
export class SomeController {
  constructor(@Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger, private readonly service: SomeService) {
    // ...
  }

  ...
}

The application tries to start but fails at some point:

2020-04-06T18:51:08.779Z [info] - Starting Nest application...
2020-04-06T18:51:08.787Z [error] - Nest can't resolve dependencies of the SomeController (?, SomeService). Please make sure that the argument winston at index [0] is available in the AppModule context.

Potential solutions:
- If winston is a provider, is it part of the current AppModule?
- If winston is exported from a separate @Module, is that module imported within AppModule?
  @Module({
    imports: [ /* the Module containing winston */ ]
  })
like image 592
x80486 Avatar asked Apr 06 '20 18:04

x80486


Video Answer


2 Answers

Try importing the WinstonModule in the root AppModule, as explained in the official docs: https://github.com/gremo/nest-winston:

import { Module } from '@nestjs/common';
import { WinstonModule } from 'nest-winston';
import * as winston from 'winston';

const logger: LoggerConfig = new LoggerConfig();    

@Module({
  imports: [WinstonModule.forRoot(logger.console())],
})
export class AppModule {}

It's probably a good idea to create some kind of factory/Logging-Config in order not to have to duplicate the logger options.

import winston, { format, transports } from "winston";

export class LoggerConfig {
  private readonly options: winston.LoggerOptions;

  constructor() {
    this.options = {
      exitOnError: false,
      format: format.combine(format.colorize(), format.timestamp(), format.printf(msg => {
        return `${msg.timestamp} [${msg.level}] - ${msg.message}`;
      })),
      transports: [new transports.Console({ level: "debug" })], // alert > error > warning > notice > info > debug
    };
  }

  public console(): object {
    return this.options;
  }
}
like image 57
eol Avatar answered Sep 22 '22 17:09

eol


Implement Winston custom logger in NestJs project

Prerequisit:

npm install --save nest-winston winston winston-daily-rotate-file

import { NestFactory } from '@nestjs/core';
import { WinstonModule } from 'nest-winston';
import * as winston from 'winston';
import * as winstonDailyRotateFile from 'winston-daily-rotate-file';

import { AppModule } from './app.module';

const transports = {
  console: new winston.transports.Console({
    level: 'silly',
    format: winston.format.combine(
      winston.format.timestamp({
        format: 'YYYY-MM-DD HH:mm:ss',
      }),
      winston.format.colorize({
        colors: {
          info: 'blue',
          debug: 'yellow',
          error: 'red',
        },
      }),
      winston.format.printf((info) => {
        return `${info.timestamp} [${info.level}] [${
          info.context ? info.context : info.stack
        }] ${info.message}`;
      }),
      // winston.format.align(),
    ),
  }),
  combinedFile: new winstonDailyRotateFile({
    dirname: 'logs',
    filename: 'combined',
    extension: '.log',
    level: 'info',
  }),
  errorFile: new winstonDailyRotateFile({
    dirname: 'logs',
    filename: 'error',
    extension: '.log',
    level: 'error',
  }),
};

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useLogger(
    WinstonModule.createLogger({
      format: winston.format.combine(
        winston.format.timestamp({
          format: 'YYYY-MM-DD HH:mm:ss',
        }),
        winston.format.errors({ stack: true }),
        winston.format.splat(),
        winston.format.json(),
      ),
      transports: [
        transports.console,
        transports.combinedFile,
        transports.errorFile,
      ],
    }),
  );
  await app.listen(4000);
}
bootstrap();

NestJs Custom Logger

NestJs Winston NPM Documentation

Note Log Levels, file names, dateformat you may edit as per your requirement. Follow officials documentations with more option.

like image 43
Dipan Mandal Avatar answered Sep 25 '22 17:09

Dipan Mandal