0

I am trying to log all express logs and unhandled exceptions in a file using nest - winston. Followed following articles ::

  1. https://www.npmjs.com/package/nest-winston
  2. https://www.section.io/engineering-education/logging-with-winston/
  3. Node.js - logging / Use morgan and winston

I researched about it and found that one should use morgan for logging express logs.

const winston = require("winston");
const morgan = require("morgan");

async function bootstrap() {
  const appOptions = {
    cors: true,
    logger: WinstonModule.createLogger({
      transports: [
        new winston.transports.Console({}),   // ==> 1
        new winston.transports.File({
          filename:
            "logs/Combined-" + new Date(Date.now()).toDateString() + ".log",
          level: "info",
          handleExceptions: true,
             }),
        new winston.transports.File({
          filename:
            "logs/Errors-" + new Date(Date.now()).toDateString() + ".log",
          level: "error",
        }),
      ],

      format: winston.format.combine(
        winston.format.timestamp({
          format: "MMM-DD-YYYY HH:mm:ss",
        }),
        winston.format.printf(
          (error) => `${error.level}: ${[error.timestamp]}: ${error.message}`
        )
      ),
    }),
  };
  const app = await NestFactory.create(ApplicationModule, appOptions);
  app.setGlobalPrefix("api");
  
  app.use(morgan("combined", { stream: winston.stream.write }));  // ==> 2

  const options = new DocumentBuilder()
    .setTitle("xx")
    .setDescription("xx")
    .setVersion("1.0")
    .setBasePath("api")
    .addBearerAuth()
    .build();
  const document = SwaggerModule.createDocument(app, options);
  SwaggerModule.setup("/docs", app, document);

  await app.listen(3000);
}
bootstrap();

Winston is correctly logging the data to the files.

error: Jul-08-2021 18:12:34: Input data validation failed
error: Jul-08-2021 18:26:28: Input data validation failed
error: Jul-08-2021 18:27:09: Input data validation failed
error: Jul-08-2021 20:57:52: Input data validation failed
info: Jul-08-2021 21:47:40: Mapped {/api/pricing/:id, GET} route
info: Jul-08-2021 21:47:40: Mapped {/api/route/:slug, DELETE} route
info: Jul-08-2021 21:47:40: Nest application successfully started

Now I wanna log all the express logs for which I inserted morgan, as shown in code (Point 2).It logs to the console, but doesnt log to the file. But if I comment out point 1 , ie logging to console. The project doesn't start. It gets stuck after below 2 lines. I waited for 15 mins but no progress.

[nodemon] restarting due to changes...
[nodemon] starting `node ./index index.js`
Dhaval Patel
  • 53
  • 2
  • 6
  • Did you consider using a nest-winston and have you managed to solve the problem? – Ren Dec 21 '21 at 13:17

2 Answers2

0

Sorry for the late response. I have used a nest winston for logging exceptions and a middleware which logs the express queries.

My main.ts file looks like this.

import { NestFactory } from "@nestjs/core";
import { DocumentBuilder, SwaggerModule } from "@nestjs/swagger";
import { WinstonModule } from "nest-winston";
import { transports } from "winston";
import { ApplicationModule } from "./app.module";
const winston = require("winston");

async function bootstrap() {
  const appOptions = {
    cors: true,
    logger: WinstonModule.createLogger({
      transports: [
        // new winston.transports.Console({}),
        new winston.transports.File({
          filename:
            "logs/Combined-" + new Date(Date.now()).toDateString() + ".log",
          level: "info",
          handleExceptions: true,
             }),
        new winston.transports.File({
          filename:
            "logs/Errors-" + new Date(Date.now()).toDateString() + ".log",
          level: "error",
        }),
      ],
      exceptionHandlers: [
        new transports.File({ filename: 'logs/exceptions.log' })
      ],
      
      format: winston.format.combine(
        winston.format.timestamp({
          format: "DD/MM/YYYY, HH:mm:ss",
        }),
        winston.format.printf(
          (error) => `[Nest] 5277   - ${[error.timestamp]}  [${error.context}] :  ${error.level}: ${error.message}`
        )
      ),
    }),
  };
  const app = await NestFactory.create(ApplicationModule, appOptions);
  
  app.setGlobalPrefix("api");
  
  const options = new DocumentBuilder()
    .setTitle("xxx")
    .setDescription("xxx")
    .setVersion("1.0")
    .setBasePath("api")
    .addBearerAuth()
    .build();
  const document = SwaggerModule.createDocument(app, options);
  SwaggerModule.setup("/docs", app, document);

  await app.listen(3000);
}
bootstrap();

Middleware Configuration looks like this.


import { Injectable, Logger, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
  private logger = new Logger('HTTP');

  use(request: Request, response: Response, next: NextFunction): void {
    const { ip, method, originalUrl } = request;
    const userAgent = request.get('user-agent') || '';

    response.on('finish', () => {
      const { statusCode } = response;
      const contentLength = response.get('content-length');

      this.logger.log(
        `${method} ${originalUrl} ${statusCode} ${contentLength} - ${userAgent} ${ip}`,
      );
    });

    next();
  }
}

Finally I have configured my middleware in app.module.ts

export class ApplicationModule implements NestModule{
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(LoggerMiddleware).forRoutes('*');
  }
  constructor(private readonly connection: Connection) {}
}
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Dhaval Patel
  • 53
  • 2
  • 6
-1

It's too late to answer this questions for future usage and challenge You can configure nestjs application to use winston logger and log into file with the following configurations

In the main.ts add these code


// Import these two line
import { WinstonModule } from 'nest-winston';
import * as winston from 'winston';

async function bootstrap() {
  const app = await NestFactory.create(AppModule, {

    logger: WinstonModule.createLogger({
      format: winston.format.combine(
        winston.format.colorize({ all: true }),
        winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
        winston.format.json(),
        winston.format.splat(),
        winston.format.prettyPrint(),
        winston.format.label({ label: 'Smartedu' }),
      ),
      transports: [
        new winston.transports.File({
          filename: 'questions_server_error.log',
          level: 'error',
        }),
        new winston.transports.Console(),
      ],
      exceptionHandlers: [
        new winston.transports.File({ filename: 'questions_exceptions.log' }),
      ],
      exitOnError: false,
    }),
  });
}

Make sure you do npm install these two packages

npm i nest-winston
npm i winston

You can add any logger level in the transport section, refer the winston documentation Then everything should work fine

  • I got the implementation for logging the exceptions using nest winston. What I was trying to achieve is log HTTP errors in the same file. – Dhaval Patel Feb 04 '22 at 07:18