在之前 我们打印日志信息的时候 都是通过 console.log 来打印信息 ,但是这样打印 存在很多缺陷 例如没有日志的不同级别的区分不能通过开关控制是否打印等等 。而本章将要学习的Nest 提供了打印日志的 api就能很好的解决这些问题
Nest 提供了打印日志的 API 与 console.log 相比具有以下优点:
1. 日志级别控制:Nest 提供了不同级别的日志记录,如调试、信息、警告和错误。这使得开发人员可以根据需要选择要记录的详细程度。与 console.log 不同,Nest 的日志 API 允许您将不同级别的日志记录到不同的目标,例如文件、数据库或外部日志服务。
2. 可配置性:Nest 的日志 API 允许您使用各种日志器(loggers)和传输器(transports)进行自定义配置。您可以根据特定需求选择适合的日志器和传输器,以便将日志记录到不同的目标,并设置格式、过滤和其他参数。
3. 上下文信息:Nest 的日志 API 允许您在日志中添加上下文信息,例如请求 ID、用户 ID 或其他自定义信息。这有助于更好地理解和追踪日志,尤其是在调试和故障排除时。
4. 集成测试:与 console.log 不同,Nest 的日志 API 可以在集成测试中更容易进行模拟和调整。您可以使用模拟的日志器来捕获和验证应用程序打印的日志,以验证预期的行为和输出。
接下来我们来详细学习一下,实现先创建一个nest项目:
nest new logger-test
运行项目:
nest start --watch
可以看到项目启动之后也会打印了一些日志
接着我们在AppController 里创建个 logger 对象,使用它的 api 打印日志信息:
import { Controller, Get, Logger } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) { }
private logger = new Logger()
@Get()
getHello(): string {
this.logger.log('打印信息1', AppController.name)
this.logger.warn('打印信息2', AppController.name)
this.logger.debug('打印信息3', AppController.name)
this.logger.error('打印信息4', AppController.name)
this.logger.verbose('打印信息5', AppController.name)
return this.appService.getHello();
}
}
游览器访问 http://localhost:3000/ 可以看到打印出了如下信息,其中 verbose、debug、log、warn、error 是日志的级别,[] 是 context(当前所在的上下文),最后是日志的内容
且使用 Logger 打印日志信息 和 console.log 的区别是 Logger能在全局控制是否打印日志 打印哪种级别的日志 例如下面:
此外 还可以自定义日志打印的方式,我们可以定义一个实现 LoggerService 接口的类 在src目录下创建 my-logger.ts
import { LoggerService, LogLevel } from "@nestjs/common";
export class MyLogger implements LoggerService {
log(message: string, context: string) {
console.log(`---log---[${context}]---`, message)
}
error(message: string, context: string) {
console.log(`---error---[${context}]---`, message)
}
warn(message: string, context: string) {
console.log(`---warn---[${context}]---`, message)
}
}
修改 main.ts 指定自定义的 logger:
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { MyLogger } from './my-logger';
async function bootstrap() {
const app = await NestFactory.create(AppModule, {
logger: new MyLogger()
});
await app.listen(3000);
}
bootstrap();
重新启动项目之后可以看到日志打印如下:
当然这样的样式很丑 所以我们可以不自己实现 LoggerService 的全部方法,而是继承 ConsoleLogger,重写一些方法,新增 my-logger2.ts
import { ConsoleLogger } from '@nestjs/common';
export class MyLogger2 extends ConsoleLogger{
log(message: string, context: string) {
console.log(`[${context}]`,message)
}
}
可以看到只有 log 类型的日志是自定义的,其他的都是原本的方法
我们可以看到logger 有3种值,但是没法注入依赖 因为 Logger 是在容器外面,手动 new 的对象
所以下面的我们将解决这个问题 首先我们创建一个 Logger 类 创建 my-logger3.ts,添加 @Injectable() 装饰器,代表这是一个 provider
import { Inject } from '@nestjs/common';
import { ConsoleLogger, Injectable } from '@nestjs/common';
import { AppService } from './app.service';
@Injectable()
export class MyLogger3 extends ConsoleLogger{
@Inject(AppService)
private appService: AppService;
log(message, context) {
console.log(this.appService.getHello());
console.log(`[${context}]`, message);
console.log('----------')
}
}
接着在全局main.ts中使用bufferLogs ,bufferLogs 的作用是先不打印日志,把它放到 buffer 缓冲区,直到用 useLogger 指定了 Logger 并且应用初始化完毕,并使用 app.useLogger 然后使用app.get 就是从容器中取这个类的实例
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { MyLogger } from './my-logger';
import { MyLogger2 } from './my-logger2';
import { MyLogger3 } from './my-logger3';
async function bootstrap() {
const app = await NestFactory.create(AppModule, {
bufferLogs: true
});
app.useLogger(app.get(MyLogger3))
await app.listen(3000);
}
bootstrap();
最后在 app.module.ts 中引入
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { MyLogger3 } from './my-logger3';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService, MyLogger3],
})
export class AppModule { }
可以看到最后实现的日志如下,logger 里成功注入了 appService 的依赖
我们可以单独创建一个模块来放置Logger 并把这个Module 设置为全局模块,首先创建模块
nest g module logger
设置为全局模块 并使用MyLogger
import { Global, Module } from '@nestjs/common';
import { MyLogger } from 'src/my-logger';
@Global()
@Module({
providers: [MyLogger],
exports: [MyLogger]
})
export class LoggerModule { }
我们创建一个新模块:
nest g resource test
在此模块中直接注入
import { Controller, Get, Post, Body, Patch, Param, Delete, Inject } from '@nestjs/common';
import { TestService } from './test.service';
import { CreateTestDto } from './dto/create-test.dto';
import { UpdateTestDto } from './dto/update-test.dto';
import { MyLogger } from 'src/my-logger';
@Controller('test')
export class TestController {
@Inject(MyLogger)
private logger: MyLogger;
constructor(private readonly testService: TestService) { }
@Post()
create(@Body() createTestDto: CreateTestDto) {
return this.testService.create(createTestDto);
}
@Get()
findAll() {
this.logger.log('测试', TestController.name)
return this.testService.findAll();
}
@Get(':id')
findOne(@Param('id') id: string) {
return this.testService.findOne(+id);
}
@Patch(':id')
update(@Param('id') id: string, @Body() updateTestDto: UpdateTestDto) {
return this.testService.update(+id, updateTestDto);
}
@Delete(':id')
remove(@Param('id') id: string) {
return this.testService.remove(+id);
}
}
最后访问 http://localhost:3000/test 可以看到成功注入了 MyLogger