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 */ ]
})
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;
}
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With