{T}

NestJS日志系统与Winston集成

NestJS日志系统与Winston集成

学习目标:掌握 NestJS 内置日志系统,学会使用 Winston 进行日志管理和文件存储。


一、日志系统的作用

1.1 为什么需要日志

日志的作用

code
日志系统的作用:
│
├── 问题定位
│   ├── 线上问题排查
│   ├── Bug 复现分析
│   └── 性能瓶颈定位
│
├── 运行监控
│   ├── 系统运行状态
│   ├── 接口调用情况
│   └── 错误发生频率
│
├── 审计追溯
│   ├── 用户操作记录
│   ├── 数据变更记录
│   └── 安全事件追溯
│
└── 性能分析
    ├── 接口响应时间
    ├── 数据库查询时间
    └── 系统资源消耗

1.2 日志级别

NestJS 内置日志级别

级别颜色用途使用场景
error红色严重错误系统异常、数据库连接失败
warn黄色警告信息配置缺失、参数异常
log绿色一般信息接口调用、业务流程
verbose白色详细信息调试信息、详细流程
debug蓝色调试信息开发调试、变量值

Winston 日志级别(从高到低)

code
Winston 日志级别(优先级从高到低):
│
├── error    - 错误:严重问题
├── warn     - 警告:潜在问题
├── info     - 信息:重要事件(NestJS 的 log)
├── http     - HTTP:HTTP 请求
├── verbose  - 详细:详细信息
├── debug    - 调试:调试信息
└── silly    - 最低:最详细的信息

二、NestJS 内置日志系统

2.1 内置日志示例

启动应用时的日志

bash
# 正常日志(黄色)
[Nest] 12345  - 2024/01/01, 10:00:00     LOG [NestApplication] Nest application successfully started

# 错误日志(红色)
[Nest] 12345  - 2024/01/01, 10:00:00   ERROR [NestApplication] Port 3000 is already in use

2.2 关闭日志

src/main.ts

typescript
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule, {
    logger: false, // 关闭所有日志
  });
  await app.listen(3000);
}
bootstrap();

2.3 使用内置 Logger 类

src/app.controller.ts

typescript
import { Controller, Get } from '@nestjs/common';
import { Logger } from '@nestjs/common';

@Controller()
export class AppController {
  private logger = new Logger('AppModule'); // 设置模块名称

  @Get()
  getHello() {
    // 不同级别的日志
    this.logger.log('这是一条 log 信息');
    this.logger.error('这是一条 error 错误');
    this.logger.warn('这是一条 warn 警告');
    this.logger.verbose('这是一条 verbose 详细信息');
    this.logger.debug('这是一条 debug 调试信息');

    return 'Hello World';
  }
}

日志输出

code
[AppModule] 这是一条 log 信息
[AppModule] 这是一条 error 错误
[AppModule] 这是一条 warn 警告
[AppModule] 这是一条 verbose 详细信息
[AppModule] 这是一条 debug 调试信息

2.4 自定义日志级别

src/main.ts

typescript
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { Logger, LogLevel } from '@nestjs/common';

async function bootstrap() {
  // 只显示 error 和 warn 级别的日志
  const app = await NestFactory.create(AppModule, {
    logger: ['error', 'warn', 'log'] as LogLevel[],
  });
  await app.listen(3000);
}
bootstrap();

三、Winston 日志库集成

3.1 Winston 简介

Winston 特点

code
Winston 优势:
│
├── 丰富的传输方式(Transports)
│   ├── Console(控制台)
│   ├── File(文件)
│   ├── Daily Rotate File(滚动文件)
│   ├── HTTP(远程服务器)
│   └── 自定义传输
│
├── 灵活的格式化
│   ├── Timestamp(时间戳)
│   ├── JSON 格式
│   ├── 自定义格式
│   └── 颜色高亮
│
├── 多日志级别
│   ├── error、warn、info
│   ├── http、verbose、debug
│   └── silly
│
└── 集中化管理
    ├── 统一配置
    ├── 多输出目标
    └── 日志分类存储

3.2 安装依赖

bash
# 安装 nest-winston 和 winston
pnpm install nest-winston winston

# 或使用 npm
npm install nest-winston winston

# 安装滚动日志插件
pnpm install winston-daily-rotate-file

# 安装环境变量工具
pnpm install cross-env

依赖说明

包名作用
nest-winstonNestJS 的 Winston 集成模块
winstonWinston 核心库
winston-daily-rotate-file滚动日志文件插件
cross-env跨平台环境变量设置

3.3 基础集成

src/main.ts

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

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

  // 替换 NestJS 默认日志为 Winston
  app.useLogger(app.get(WINSTON_MODULE_NEST_PROVIDER));

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

src/app.module.ts

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

@Module({
  imports: [
    WinstonModule.forRoot({
      transports: [
        // 控制台输出
        new winston.transports.Console({
          format: winston.format.combine(
            winston.format.timestamp(),
            winston.format.simple(),
          ),
        }),
      ],
    }),
  ],
})
export class AppModule {}

3.4 在 Service 中使用

src/app.controller.ts

typescript
import { Controller, Get } from '@nestjs/common';
import { Logger } from '@nestjs/common';
import { Inject } from '@nestjs/common';

@Controller()
export class AppController {
  constructor(@Inject(Logger) private readonly logger: Logger) {}

  @Get()
  getHello() {
    this.logger.log('这是一条 log 信息');
    this.logger.error('这是一条 error 错误');
    this.logger.warn('这是一条 warn 警告');
    this.logger.verbose('这是一条 verbose 详细信息');
    this.logger.debug('这是一条 debug 调试信息');

    return 'Hello World';
  }
}

四、Winston 高级配置

4.1 格式化配置

src/app.module.ts

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

@Module({
  imports: [
    WinstonModule.forRoot({
      transports: [
        new winston.transports.Console({
          format: winston.format.combine(
            winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), // 时间戳
            winston.format.ms(), // 毫秒
            winston.format.colorize({ all: true }), // 颜色
            winston.format.simple(), // 简单格式
          ),
        }),
      ],
    }),
  ],
})
export class AppModule {}

格式化函数说明

函数作用示例
timestamp()添加时间戳2024-01-01 10:00:00
ms()添加毫秒+123ms
colorize()颜色高亮不同级别不同颜色
simple()简单格式info: message {"timestamp":"..."}
json()JSON 格式{"level":"info","message":"..."}
prettyPrint()美化输出多行 JSON
printf()自定义格式info: 2024-01-01 message

4.2 自定义格式

typescript
import * as winston from 'winston';

const customFormat = winston.format.printf(({ level, message, timestamp, context }) => {
  return `${timestamp} [${context || 'App'}] ${level}: ${message}`;
});

@Module({
  imports: [
    WinstonModule.forRoot({
      transports: [
        new winston.transports.Console({
          format: winston.format.combine(
            winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
            winston.format.colorize(),
            customFormat,
          ),
        }),
      ],
    }),
  ],
})
export class AppModule {}

输出示例

code
2024-01-01 10:00:00 [AppController] info: 这是一条 log 信息
2024-01-01 10:00:00 [AppController] error: 这是一条 error 错误

4.3 日志级别设置

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

@Module({
  imports: [
    WinstonModule.forRoot({
      level: 'silly', // 设置最低日志级别
      transports: [
        new winston.transports.Console({
          format: winston.format.combine(
            winston.format.timestamp(),
            winston.format.simple(),
          ),
        }),
      ],
    }),
  ],
})
export class AppModule {}

五、文件日志存储

5.1 基础文件存储

src/app.module.ts

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

@Module({
  imports: [
    WinstonModule.forRoot({
      transports: [
        // 控制台输出
        new winston.transports.Console({
          format: winston.format.combine(
            winston.format.timestamp(),
            winston.format.simple(),
          ),
        }),
        // 错误日志文件
        new winston.transports.File({
          filename: 'logs/error.log',
          level: 'error',
          format: winston.format.combine(
            winston.format.timestamp(),
            winston.format.json(),
          ),
        }),
        // 所有日志文件
        new winston.transports.File({
          filename: 'logs/combined.log',
          format: winston.format.combine(
            winston.format.timestamp(),
            winston.format.json(),
          ),
        }),
      ],
    }),
  ],
})
export class AppModule {}

生成的文件

code
logs/
├── error.log      # 只记录 error 级别
└── combined.log   # 记录所有级别

5.2 滚动日志文件

为什么需要滚动日志

code
滚动日志解决的问题:
│
├── 文件过大
│   ├── 单个文件难以打开
│   ├── 查找效率低下
│   └── 占用大量磁盘空间
│
├── 日志管理
│   ├── 按日期分类
│   ├── 自动清理过期日志
│   └── 压缩归档
│
└── 性能优化
    ├── 减少单个文件大小
    ├── 提高写入效率
    └── 便于备份恢复

安装依赖

bash
pnpm install winston-daily-rotate-file

src/app.module.ts

typescript
import { Module } from '@nestjs/common';
import { WinstonModule } from 'nest-winston';
import * as winston from 'winston';
import DailyRotateFile from 'winston-daily-rotate-file';

// 创建滚动日志传输器
const createDailyRotateTransport = (level: string, filename: string) => {
  return new DailyRotateFile({
    level,
    filename: `logs/${filename}-%DATE%.log`,
    datePattern: 'YYYY-MM-DD-HH',
    zippedArchive: true,
    maxSize: '20m',
    maxFiles: '14d',
    format: winston.format.combine(
      winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
      winston.format.simple(),
    ),
  });
};

@Module({
  imports: [
    WinstonModule.forRoot({
      transports: [
        // 控制台输出
        new winston.transports.Console({
          format: winston.format.combine(
            winston.format.timestamp(),
            winston.format.simple(),
          ),
        }),
        // 错误日志滚动文件
        createDailyRotateTransport('error', 'error'),
        // 所有日志滚动文件
        createDailyRotateTransport('info', 'app'),
      ],
    }),
  ],
})
export class AppModule {}

配置参数说明

参数类型作用示例
filenamestring文件名模式logs/error-%DATE%.log
datePatternstring日期模式YYYY-MM-DD-HH
zippedArchiveboolean是否压缩归档true
maxSizestring最大文件大小20m(20MB)
maxFilesstring最大保存时间14d(14天)
levelstring日志级别errorinfo

生成的文件

code
logs/
├── error-2024-01-01-10.log.gz    # 压缩的错误日志
├── error-2024-01-01-11.log.gz
├── app-2024-01-01-10.log.gz      # 压缩的应用日志
└── app-2024-01-01-11.log.gz

5.3 日志格式对比

JSON 格式(适合日志分析)

json
{
  "level": "info",
  "message": "User logged in",
  "timestamp": "2024-01-01T10:00:00.000Z",
  "context": "AuthService",
  "userId": 123,
  "ip": "192.168.1.1"
}

Simple 格式(适合人类阅读)

code
2024-01-01 10:00:00 info: User logged in {"context":"AuthService","userId":123}

自定义格式(最灵活)

code
[2024-01-01 10:00:00] [AuthService] INFO: User logged in (userId: 123)

六、环境区分配置

6.1 使用 cross-env 设置环境变量

安装 cross-env

bash
pnpm install cross-env

package.json

json
{
  "scripts": {
    "start:dev": "cross-env NODE_ENV=development nest start --watch",
    "start": "cross-env NODE_ENV=development nest start",
    "start:prod": "cross-env NODE_ENV=production node dist/main",
    "build": "cross-env NODE_ENV=production nest build"
  }
}

6.2 根据环境配置日志

src/app.module.ts

typescript
import { Module } from '@nestjs/common';
import { WinstonModule } from 'nest-winston';
import * as winston from 'winston';
import DailyRotateFile from 'winston-daily-rotate-file';

// 判断是否为开发环境
const isDev = process.env.NODE_ENV === 'development';

// 创建滚动日志传输器
const createDailyRotateTransport = (level: string, filename: string) => {
  return new DailyRotateFile({
    level,
    filename: `logs/${filename}-%DATE%.log`,
    datePattern: 'YYYY-MM-DD-HH',
    zippedArchive: true,
    maxSize: '20m',
    maxFiles: '14d',
    format: winston.format.combine(
      winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
      winston.format.simple(),
    ),
  });
};

@Module({
  imports: [
    WinstonModule.forRoot({
      level: isDev ? 'silly' : 'info', // 开发环境显示所有日志,生产环境只显示 info 以上
      transports: [
        // 控制台输出(开发和生产都启用)
        new winston.transports.Console({
          format: winston.format.combine(
            winston.format.timestamp(),
            winston.format.simple(),
          ),
        }),
        // 文件日志(仅生产环境启用)
        ...(!isDev
          ? [
              createDailyRotateTransport('error', 'error'),
              createDailyRotateTransport('info', 'app'),
            ]
          : []),
      ],
    }),
  ],
})
export class AppModule {}

配置逻辑

code
环境配置策略:
│
├── 开发环境(NODE_ENV=development)
│   ├── 日志级别:silly(所有日志)
│   ├── 输出目标:控制台
│   └── 不生成日志文件
│
└── 生产环境(NODE_ENV=production)
    ├── 日志级别:info(info 以上)
    ├── 输出目标:控制台 + 文件
    └── 滚动日志文件(自动清理)

6.3 环境变量配置文件

.env.development

env
NODE_ENV=development
LOG_LEVEL=silly

.env.production

env
NODE_ENV=production
LOG_LEVEL=info

src/app.module.ts

typescript
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { WinstonModule } from 'nest-winston';
import * as winston from 'winston';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      envFilePath: [`.env.${process.env.NODE_ENV || 'development'}`],
    }),
    WinstonModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (configService: ConfigService) => {
        const isDev = configService.get('NODE_ENV') === 'development';
        const logLevel = configService.get('LOG_LEVEL') || 'info';

        return {
          level: logLevel,
          transports: [
            new winston.transports.Console({
              format: winston.format.combine(
                winston.format.timestamp(),
                winston.format.simple(),
              ),
            }),
            // ... 其他配置
          ],
        };
      },
    }),
  ],
})
export class AppModule {}

七、日志最佳实践

7.1 日志内容规范

好的日志应该包含

typescript
//  好的日志示例
this.logger.log(`User ${userId} logged in from ${ip}`);
this.logger.error(`Database connection failed: ${error.message}`, error.stack);
this.logger.warn(`API rate limit exceeded for user ${userId}`);
this.logger.debug(`Request body: ${JSON.stringify(body)}`);

//  不好的日志示例
this.logger.log('User logged in'); // 缺少上下文
this.logger.error('Error'); // 没有错误详情
this.logger.warn('Something wrong'); // 没有具体信息

日志分类

code
日志分类:
│
├── 业务日志
│   ├── 用户登录/登出
│   ├── 订单创建/支付
│   └── 关键业务操作
│
├── 系统日志
│   ├── 应用启动/关闭
│   ├── 数据库连接
│   └── 缓存操作
│
├── 错误日志
│   ├── 未捕获异常
│   ├── 数据库错误
│   └── 第三方服务错误
│
└── 调试日志
    ├── 变量值
    ├── 执行流程
    └── 性能数据

7.2 日志中间件

src/common/middleware/logger.middleware.ts

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

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

  use(req: Request, res: Response, next: NextFunction) {
    const { method, originalUrl } = req;
    const startTime = Date.now();

    res.on('finish', () => {
      const { statusCode } = res;
      const responseTime = Date.now() - startTime;

      this.logger.log(
        `${method} ${originalUrl} ${statusCode} - ${responseTime}ms`
      );
    });

    next();
  }
}

在模块中应用

typescript
import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { LoggerMiddleware } from './common/middleware/logger.middleware';

@Module({})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(LoggerMiddleware).forRoutes('*');
  }
}

7.3 异常过滤器日志

src/common/filters/http-exception.filter.ts

typescript
import {
  ExceptionFilter,
  Catch,
  ArgumentsHost,
  HttpException,
  HttpStatus,
} from '@nestjs/common';
import { Request, Response } from 'express';
import { Logger } from '@nestjs/common';

@Catch()
export class HttpExceptionFilter implements ExceptionFilter {
  private readonly logger = new Logger(HttpExceptionFilter.name);

  catch(exception: unknown, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();

    const status =
      exception instanceof HttpException
        ? exception.getStatus()
        : HttpStatus.INTERNAL_SERVER_ERROR;

    const message =
      exception instanceof HttpException
        ? exception.getResponse()
        : 'Internal server error';

    // 记录错误日志
    this.logger.error(
      `${request.method} ${request.url} - ${status} - ${JSON.stringify(message)}`,
      exception instanceof Error ? exception.stack : undefined
    );

    response.status(status).json({
      statusCode: status,
      timestamp: new Date().toISOString(),
      path: request.url,
      message,
    });
  }
}

7.4 性能监控日志

src/common/interceptors/logging.interceptor.ts

typescript
import {
  Injectable,
  NestInterceptor,
  ExecutionContext,
  CallHandler,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
import { Logger } from '@nestjs/common';

@Injectable()
export class LoggingInterceptor implements NestInterceptor {
  private logger = new Logger('Performance');

  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const request = context.switchToHttp().getRequest();
    const { method, url } = request;
    const startTime = Date.now();

    return next.handle().pipe(
      tap(() => {
        const responseTime = Date.now() - startTime;

        if (responseTime > 1000) {
          // 超过 1 秒的慢请求
          this.logger.warn(
            `Slow request: ${method} ${url} took ${responseTime}ms`
          );
        } else {
          this.logger.debug(`${method} ${url} took ${responseTime}ms`);
        }
      })
    );
  }
}

八、完整配置示例

8.1 项目结构

code
project/
├── src/
│   ├── common/
│   │   ├── filters/
│   │   │   └── http-exception.filter.ts
│   │   ├── interceptors/
│   │   │   └── logging.interceptor.ts
│   │   └── middleware/
│   │       └── logger.middleware.ts
│   ├── config/
│   │   └── winston.config.ts
│   ├── app.module.ts
│   └── main.ts
├── logs/                    # 日志文件目录(生产环境)
│   ├── error-2024-01-01.log.gz
│   └── app-2024-01-01.log.gz
├── .env.development
├── .env.production
└── package.json

8.2 Winston 配置文件

src/config/winston.config.ts

typescript
import * as winston from 'winston';
import DailyRotateFile from 'winston-daily-rotate-file';

const isDev = process.env.NODE_ENV === 'development';

// 创建滚动日志传输器
const createDailyRotateTransport = (level: string, filename: string) => {
  return new DailyRotateFile({
    level,
    filename: `logs/${filename}-%DATE%.log`,
    datePattern: 'YYYY-MM-DD-HH',
    zippedArchive: true,
    maxSize: '20m',
    maxFiles: '14d',
    format: winston.format.combine(
      winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
      winston.format.simple(),
    ),
  });
};

// Winston 配置
export const winstonConfig = {
  level: isDev ? 'silly' : 'info',
  transports: [
    // 控制台输出
    new winston.transports.Console({
      format: winston.format.combine(
        winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
        winston.format.colorize({ all: true }),
        winston.format.simple(),
      ),
    }),
    // 文件日志(仅生产环境)
    ...(!isDev
      ? [
          createDailyRotateTransport('error', 'error'),
          createDailyRotateTransport('info', 'app'),
        ]
      : []),
  ],
};

8.3 AppModule 配置

src/app.module.ts

typescript
import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { WinstonModule } from 'nest-winston';
import { winstonConfig } from './config/winston.config';
import { LoggerMiddleware } from './common/middleware/logger.middleware';

@Module({
  imports: [WinstonModule.forRoot(winstonConfig)],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(LoggerMiddleware).forRoutes('*');
  }
}

8.4 main.ts 配置

src/main.ts

typescript
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston';
import { HttpExceptionFilter } from './common/filters/http-exception.filter';
import { LoggingInterceptor } from './common/interceptors/logging.interceptor';

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

  // 使用 Winston 日志
  app.useLogger(app.get(WINSTON_MODULE_NEST_PROVIDER));

  // 全局异常过滤器
  app.useGlobalFilters(new HttpExceptionFilter());

  // 全局拦截器
  app.useGlobalInterceptors(new LoggingInterceptor());

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

九、常见问题与解决方案

9.1 日志文件过大

问题:单个日志文件过大,难以打开和查找

解决方案

typescript
//  使用滚动日志文件
new DailyRotateFile({
  maxSize: '20m',  // 最大 20MB
  maxFiles: '14d', // 保留 14 天
  zippedArchive: true, // 自动压缩
});

9.2 日志级别不正确

问题:debug 日志在生产环境输出

解决方案

typescript
//  根据环境设置日志级别
const isDev = process.env.NODE_ENV === 'development';

const winstonConfig = {
  level: isDev ? 'silly' : 'info', // 生产环境只显示 info 以上
  // ...
};

9.3 日志丢失上下文

问题:日志缺少关键信息,难以定位问题

解决方案

typescript
//  添加上下文信息
this.logger.error(
  `User login failed: userId=${userId}, ip=${ip}`,
  error.stack,
  'AuthService'
);

9.4 日志格式不统一

问题:不同模块日志格式不一致

解决方案

typescript
//  使用统一的格式化函数
const logFormat = winston.format.printf(({ level, message, timestamp, context }) => {
  return `${timestamp} [${context || 'App'}] ${level}: ${message}`;
});

十、学习要点总结

10.1 核心概念速记

code
NestJS 日志系统核心概念:
│
├── 内置日志
│   ├── Logger 类
│   ├── 5 个日志级别:log、error、warn、verbose、debug
│   └── 可关闭或自定义日志级别
│
├── Winston 集成
│   ├── nest-winston 模块
│   ├── 替换默认日志:app.useLogger()
│   ├── 多种 transports:Console、File、DailyRotateFile
│   └── 灵活的格式化:timestamp、colorize、simple
│
├── 文件日志
│   ├── 基础文件:File transport
│   ├── 滚动日志:winston-daily-rotate-file
│   └── 自动清理:maxSize、maxFiles
│
└── 环境区分
    ├── cross-env 设置环境变量
    ├── 开发环境:控制台 + 所有日志
    └── 生产环境:控制台 + 文件 + info 以上日志

10.2 重点知识清单

知识点重要程度掌握程度
日志的作用和级别未掌握 / 已掌握
NestJS 内置 Logger未掌握 / 已掌握
Winston 基础集成未掌握 / 已掌握
Winston 格式化未掌握 / 已掌握
文件日志存储未掌握 / 已掌握
滚动日志配置未掌握 / 已掌握
环境区分配置未掌握 / 已掌握
日志中间件未掌握 / 已掌握

10.3 课后思考题

  1. 为什么需要日志系统?它有哪些作用?
  2. NestJS 内置的日志级别有哪些?分别用于什么场景?
  3. 如何集成 Winston 到 NestJS?
  4. 什么是滚动日志?为什么需要滚动日志?
  5. 如何根据环境区分日志配置?

参考资料


上一章22-Prisma在NestJS中的完整集成

下一章24-NestJS配置管理与环境变量