在NestJS中,nest-winston 包用于集成 Winston 日志库,以便更好地进行日志记录。以下是如何使用 nest-winston 包的基本步骤和一些配置选项:

1.安装依赖
首先,你需要安装 nest-winstonwinston 包。你可以使用 pnpm 或 yarn 来安装这些依赖。

pnpm install nest-winston winston
安装winston-daily-rotate-file使日志可以本地按天轮转
pnpm install winston-daily-rotate-file

2.配置 WinstonModule
AppModule 中配置 WinstonModule。下面是一个示例配置:

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { utilities as nestWinstonModuleUtilities, WinstonModule } from 'nest-winston';
import * as winston from 'winston';
import 'winston-daily-rotate-file';

@Module({
  imports: [
   WinstonModule.forRoot({
  transports: [
    new winston.transports.Console({
      // 结合多个格式化器来定义控制台日志的输出格式
      format: winston.format.combine(
        // 添加时间戳到日志中
        winston.format.timestamp(),
        // 添加毫秒数到日志中
        winston.format.ms(),
        // 使用 nest-winston 提供的 nestLike 格式化器,使日志更符合 NestJS 的风格
        nestWinstonModuleUtilities.format.nestLike('NestjsFrame', {
          colors: true, // 使用颜色来区分不同的日志级别
          prettyPrint: true, // 以更易读的格式打印日志
          processId: true, // 添加进程 ID 到日志中
          appName: true, // 添加应用名称到日志中
        }),
      ),
    }),
    new winston.transports.DailyRotateFile({
      dirname: 'logs', // 日志文件存储的目录
      level: 'info', // 记录 info 级别及以上的日志
      filename: 'NestjsFrame-%DATE%.log', // 日志文件名格式,%DATE% 会被替换为日期
      datePattern: 'YYYY-MM-DD-HH', // 日期格式,用于生成日志文件名中的日期部分
      zippedArchive: true, // 是否将旧的日志文件压缩
      maxSize: '20m', // 单个日志文件的最大大小,超过这个大小会创建新的日志文件
      maxFiles: '14d', // 保留日志文件的最大天数
      // 结合多个格式化器来定义文件日志的输出格式
      format: winston.format.combine(
        // 添加时间戳到日志中
        winston.format.timestamp(),
        // 使用简单的格式化器
        winston.format.simple(),
      ),
    }),
  ],
}),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

3.使用日志服务
在你的服务或控制器中注入 @Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger 并使用它来记录日志。

import { Controller, Get, Inject } from '@nestjs/common';
import { AppService } from './app.service';
import { WINSTON_MODULE_PROVIDER } from 'nest-winston'
import { Logger } from 'winston';
@Controller()
export class AppController {
  constructor(
    private readonly appService: AppService,
    @Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger

  ) { }

  @Get()
  getHello(): string {
    this.logger.info('Hello World!', AppController.name);
    this.logger.warn('Hello World!', AppController.name);
    this.logger.error('Hello World!', AppController.name);
    return this.appService.getHello();
  }
}

4.推荐的用法

main.ts 中使用 useLogger 更换默认日志记录器,这样我们在使用的时可以直接使用 NestJS 内置的 Logger 就可以。

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston';
import { HttpFilter } from './http.filter';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useLogger(app.get(WINSTON_MODULE_NEST_PROVIDER));
  app.useGlobalFilters(new HttpFilter())
  await app.listen(process.env.PORT ?? 3000);
}
bootstrap();

在某个业务或者控制器使用Logger:从'@nestjs/common'引入new一个即可。

import { Injectable, Logger } from '@nestjs/common';

@Injectable()
export class UserService {
  private logger = new Logger('UserService');

  async create(createUserDto: CreateUserDto) {
    this.logger.log('@@@@ 创建用户参数:', createUserDto);
    // ...业务逻辑
  }

  async findAll(query: ListUserDto) {
    try {
      // ...业务逻辑
    } catch (error) {
      this.logger.error('@@@@ 账号列表查询失败:', error);
      throw new InternalServerErrorException('账号列表查询失败');
    }  
  }
}

通过以上步骤,你可以在 NestJS 应用中使用 nest-winston 包来记录日志。根据你的需求,你可以进一步自定义日志的格式、输出位置和级别。

5.优化一下

AppModule里winston配置一大坨,并不美观,抽离一下,新建logger.config.ts

import { createLogger, format } from 'winston';
import { utilities as nestWinstonModuleUtilities } from 'nest-winston';
import 'winston-daily-rotate-file';
import * as winston from 'winston';

const winstonLogger = createLogger({
  format: format.combine(
    format.timestamp(),
    format.errors({ stack: true }),
    format.splat(),
    format.json(),
  ),
  defaultMeta: { service: 'log-service' },
  transports: [
    new winston.transports.DailyRotateFile({
      dirname: 'logs/info', // 日志文件存储的目录
      level: 'info', // 记录 info 级别及以上的日志
      filename: 'info-%DATE%.log', // 日志文件名格式,%DATE% 会被替换为日期
      datePattern: 'YYYY-MM-DD-HH', // 日期格式,用于生成日志文件名中的日期部分
      zippedArchive: true, // 是否将旧的日志文件压缩
      maxSize: '20m', // 单个日志文件的最大大小,超过这个大小会创建新的日志文件
      maxFiles: '14d', // 保留日志文件的最大天数
      // 结合多个格式化器来定义文件日志的输出格式
      format: winston.format.combine(
        // 添加时间戳到日志中
        winston.format.timestamp(),
        // 使用简单的格式化器
        winston.format.simple(),
      ),
    }),
    new winston.transports.DailyRotateFile({
      dirname: 'logs/error',
      level: 'error',
      filename: 'error-%DATE%.log',
      datePattern: 'YYYY-MM-DD-HH',
      zippedArchive: true,
      maxSize: '20m',
      maxFiles: '14d',
      format: winston.format.combine(
        winston.format.timestamp(),
        winston.format.simple(),
      ),
    }),
    new winston.transports.DailyRotateFile({
      dirname: 'logs/warn',
      level: 'warn',
      filename: 'warn-%DATE%.log',
      datePattern: 'YYYY-MM-DD-HH',
      zippedArchive: true,
      maxSize: '20m',
      maxFiles: '14d',
      format: winston.format.combine(
        winston.format.timestamp(),
        winston.format.simple(),
      ),
    }),

    new winston.transports.Console({
      // 结合多个格式化器来定义控制台日志的输出格式
      format: winston.format.combine(
        winston.format.timestamp(),
        winston.format.ms(),
        // 使用 nest-winston 提供的 nestLike 格式化器,使日志更符合 NestJS 的风格
        nestWinstonModuleUtilities.format.nestLike('NestjsFrame', {
          colors: true, // 使用颜色来区分不同的日志级别
          prettyPrint: true, // 以更易读的格式打印日志
          processId: true, // 添加进程 ID 到日志中
          appName: true, // 添加应用名称到日志中
        }),
      ),
    }),


  ],
});

export default winstonLogger;

优化后的AppModule

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { WinstonModule } from 'nest-winston';
import winstonLogger from './config/logger.config';
@Module({
  imports: [WinstonModule.forRoot({
    transports: winstonLogger.transports,
    format: winstonLogger.format,
    defaultMeta: winstonLogger.defaultMeta,
    exitOnError: false,
  }),],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule { }
最后修改:2025 年 03 月 12 日
如果觉得我的文章对你有用,请随意赞赏