NestJS:如何自定义日志消息以包含日志消息发生的请求 ID 和文件名

NestJS: How to customise log messages to include request id and name of the file the log message occurred

我是 NestJS 的新手,想自定义日志消息以包含 x-request-id/x-correlation-id 和日志消息来源的文件名,但我不确定 NestJS 中是否有任何东西可以做到这一点。

我的应用程序将 NestJS 与 Fastify 适配器一起使用,并且在 bootstrap() 函数中具有以下配置

  const app = await NestFactory.create<NestFastifyApplication>(
    AppModule,
    new FastifyAdapter(),
    {
        logger: WinstonModule.createLogger(winston.createLogger({
          exitOnError: false,
          level: 'debug',
          handleExceptions: true,
          format: winston.format.combine(
            winston.format.timestamp(),
            winston.format.ms(),
            winston.format.colorize(),
            winston.format.align(),
            winston.format.splat(),
            winston.format.printf((info) => {
                return `${info.timestamp} [ ${info.level} ] : ${info.message}`;
            }),
          ),
          transports: [
            new (winston.transports.Console)()
          ]
        }),
      )
    }
  );

这似乎按预期使用 winston 格式化了日志。

2022-03-09T11:21:22.131Z [ info ] : Starting Nest application...

不过,我还想在消息中包含 request/correlation id 以及日志消息出现的文件名,例如

2022-03-09T11:21:22.131Z 2cfd4eee-ca2b-4869-b66b-2b7da291f567 [ info ] [ Main.ts ]: Starting Nest application...

NestJS 本身是否有任何允许我可以使用这个或任何外部库来达到预期结果的东西?

  1. 分配请求 ID。将其作为您的第一个 middleware.
  2. 将请求上下文与 logger 绑定。制作 Logger 的 class,将 request context 绑定到记录器。它基本上充当 WinstonLogger 的包装器。覆盖 winston logger 的所有方法,以您想要的方式打印请求 ID(首选方式是使用 JSON,因为这样您可以更轻松地在日志中查询)。

我设法使用 nest-pino 库让它工作:

// main.ts

import { Logger } from 'nestjs-pino';

async function bootstrap() {

const app = await NestFactory.create<NestFastifyApplication>(
    AppModule,
    new FastifyAdapter(),
    { bufferLogs: true }
  );

  app.useLogger(app.get(Logger));
  
}
bootstrap();

// app.module.ts

import { LoggerModule } from 'nestjs-pino';

@Module({
  imports: [
    LoggerModule.forRoot({
      pinoHttp: {
        level: process.env.LOG_LEVEL || 'debug',
        redact: ['request.headers.authorization'],
        prettyPrint: {
          colorize: true,
          singleLine: true,
          levelFirst: false,
          translateTime: "yyyy-MM-dd'T'HH:mm:ss.l'Z'",
          messageFormat: "{req.headers.x-correlation-id} [{context}] {msg}",
          ignore: "pid,hostname,context,req,res,responseTime",
          errorLikeObjectKeys: ['err', 'error']
        }
      }
    }),
  ],
  controllers: [MyController],
})
export class AppModule {}

// my.controller.ts
import { Controller, Get, Param, Logger } from '@nestjs/common';

@Controller()
export class MyController {
    private readonly logger: Logger = new Logger(MyController.name);

    @Get('/:id')
    async getCustomerDetails(@Headers() headers, @Param('id') id: string): Promise<Customer> {
        this.logger.log(`Accepted incoming request with id: ${id}`);

        // Do some processing ....

        return customer;
    }
}

[2022-11-14T11:03:07.100Z] INFO: 428f0df9-d12b-4fca-9b11-805a13ff41be [MyController] Accepted incoming request with id: 1