Skip to content

NestJS 日志系统初探

1. NestJS 自带日志

NestJS 内置了基于 ConsoleLogger 的日志系统,支持以下级别:

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

const logger = new Logger('AppContext');

logger.log('普通日志');
logger.error('错误日志');
logger.warn('警告日志');
logger.debug('调试日志');
logger.verbose('详细日志');

2. 自定义日志器

继承 ConsoleLogger 并覆盖方法

typescript
// my-logger.service.ts
import { ConsoleLogger } from '@nestjs/common';

export class MyLogger extends ConsoleLogger {
  log(message: any, context?: string) {
    // 自定义逻辑
    super.log(message, context);
  }

  error(message: any, stack?: string, context?: string) {
    super.error(message, stack, context);
  }

  warn(message: any, context?: string) {
    super.warn(message, context);
  }

  debug(message: any, context?: string) {
    super.debug(message, context);
  }

  verbose(message: any, context?: string) {
    super.verbose(message, context);
  }
}

3. 创建 LoggerModule

typescript
// my-logger.module.ts
import { Module, Global } from '@nestjs/common';
import { MyLogger } from './my-logger.service';

@Global()  // 全局模块,其他模块无需显式导入
@Module({
  providers: [MyLogger],
  exports: [MyLogger],
})
export class LoggerModule {}

4. 让 Nest 框架使用自定义日志器

main.ts 中设置:

typescript
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { MyLogger } from './my-logger/my-logger.service';

async function bootstrap() {
  const app = await NestFactory.create(AppModule, {
    bufferLogs: true,  // 缓冲日志,直到自定义日志器就绪
  });

  // 关键:让 Nest 框架本身使用 MyLogger
  app.useLogger(app.get(MyLogger));

  await app.listen(3000);
}
配置作用
bufferLogs: true启动期间缓冲日志,避免丢失
app.useLogger()让框架日志(路由、异常等)使用自定义 logger

5. 业务模块使用依赖注入

在 AppModule 中导入 LoggerModule(必须,用于初始化):

typescript
// app.module.ts
import { LoggerModule } from './my-logger/my-logger.module';

@Module({
  imports: [LoggerModule],  // 必须导入
  // ...
})
export class AppModule {}

在任何 Service/Ctorller 中注入使用

typescript
// app.service.ts
import { Injectable } from '@nestjs/common';
import { MyLogger } from './my-logger/my-logger.service';

@Injectable()
export class AppService {
  constructor(private readonly myLogger: MyLogger) {}

  getHello() {
    this.myLogger.log('getHello called');
    return 'Hello World';
  }
}

6. 架构关系图

┌─────────────────────────────────────────────────────────────┐
│                          NestJS 应用                         │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  main.ts: app.useLogger(app.get(MyLogger))  ←── 框架日志     │
│                           │                                  │
│                           ▼                                  │
│  ┌───────────────────────────────────────────────────────┐  │
│  │              LoggerModule (@Global)                    │  │
│  │  ├── providers: [MyLogger]                            │  │
│  │  └── exports: [MyLogger]                              │  │
│  └───────────────────────────────────────────────────────┘  │
│                           │                                  │
│                           ▼                                  │
│  ┌───────────────────────────────────────────────────────┐  │
│  │                    MyLogger                           │  │
│  │         extends ConsoleLogger                         │  │
│  └───────────────────────────────────────────────────────┘  │
│                           │                                  │
│           ┌───────────────┴───────────────┐                 │
│           ▼                               ▼                 │
│    ┌─────────────┐              ┌─────────────┐             │
│    │ AppService  │              │ UserService │             │
│    │ 注入使用    │              │ 注入使用    │             │
│    └─────────────┘              └─────────────┘             │
│                                                             │
└─────────────────────────────────────────────────────────────┘

7. 关键要点

概念说明
@Global()标记后,其他模块无需 imports 即可使用
bufferLogs: true启动期间缓冲日志,确保不丢失
app.useLogger()必须,让框架日志也走自定义 logger
AppModule 导入即使是全局模块,也需在某处导入来初始化
依赖注入推荐,优于手动 new MyLogger()

8. 日志级别

级别用途
log一般信息
error错误
warn警告
debug调试(开发用)
verbose详细追踪(最底层)

基于 VitePress 构建