前言
在平常的前端开发工作和运维搬砖工作中,我们离不开日志。比如我们可以通过打印的日志去观察应用的运行状态,或者查看上下文和变量的值等,或者排查和定位线上问题等等。在 Nest 后端应用中,也不例外,学会打印和查看日志也是掌握 Nest 的很重要的一环。
这里,我们将探索 Nest 中常用的打印日志的方法。
Logger 类
在 @nestjs/common 包中包含了 Logger 类,可以用于设置日志。
在默认情况下,我们启动应用后可以看到打印了:
[Nest] 7344 - 2024/05/04 23:53:29 LOG [NestFactory] Starting Nest application...
[Nest] 7344 - 2024/05/04 23:53:29 LOG [InstanceLoader] AppModule dependencies initialized +11ms
[Nest] 7344 - 2024/05/04 23:53:29 LOG [RoutesResolver] AppController {/}: +9ms
[Nest] 7344 - 2024/05/04 23:53:29 LOG [RouterExplorer] Mapped {/, GET} route +6ms
[Nest] 7344 - 2024/05/04 23:53:29 LOG [NestApplication] Nest application successfully started +3ms
我们可以关闭 Nest 日志的打印,通过在main.ts
中设置:
const app = await NestFactory.create(AppModule, {
logger: false,
});
await app.listen(3000);
或是,设置日志打印的类型:
const app = await NestFactory.create(AppModule, {
logger: ['error', 'warn'],
});
await app.listen(3000);
可以设置的有以下几种:'log'
, 'fatal'
, 'error'
, 'warn'
, 'debug'
, and 'verbose'
。
或是设置为logger: console,
,也就是打印的是简单的样式,文本不带颜色。
与此同时,我们可以在 app.controller.ts 中,引入 Logger 打印器,设置了但访问 getHello
方法时打印相应的日志,方便后续的调试。
import { Controller, Get, Logger } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
private logger = new Logger();
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
this.logger.log('11', AppController.name);
this.logger.error('22', AppController.name);
this.logger.warn('33', AppController.name);
return this.appService.getHello();
}
}
LoggerService 接口
我们可以借助 LoggerService 接口去自定义一个日志打印器。
首先,新建 MyLogger.ts 文件,定义了三种级别的日志打印:
import { Injectable, LoggerService } from '@nestjs/common';
@Injectable()
export class MyLogger implements LoggerService {
/**
* Write a 'log' level log.
*/
log(message: any, ...optionalParams: any[]) {
console.log(`---log---`, message)
}
/**
* Write an 'error' level log.
*/
error(message: any, ...optionalParams: any[]) {
console.log(`---error---`, message)
}
/**
* Write a 'warn' level log.
*/
warn(message: any, ...optionalParams: any[]) {
console.log(`---warn---`, message)
}
}
接着,在 main.ts 中引入该类,
logger: new MyLogger(),
当启动日志时,可以看到打印了
---log--- Starting Nest application...
---log--- AppModule dependencies initialized
---log--- AppController {/}:
---log--- Mapped {/, GET} route
---log--- Nest application successfully started
当访问 http://localhost:3000/ 时,打印的是:
---log--- 11
---error--- 22
---warn--- 33
也就是生效了。
继承 ConsoleLogger
我们也可以不需要自己去实现 LoggerService 的全部方法,而是通过继承 ConsoleLogger,并重写一些方法:
import { ConsoleLogger } from '@nestjs/common';
export class MyLogger2 extends ConsoleLogger {
log(message: string, context: string) {
console.log(`log:`, message)
}
error(message: any, stack?: string, context?: string) {
console.log(`error:`, message)
}
}
我们查看对应的定义,可以发现 ConsoleLogger 继承了 LoggerService 接口,那么没重写的方法就是原来的打印内容和样式:
export declare class ConsoleLogger implements LoggerService {
// ...
}
依赖注入
为了在自定义的 logger 中启用依赖注入,我们创建一个 MyLogger3 类继承了 ConsoleLogger 类,并在模块中注册为一个 provider 。具体是:
在 main.ts 中设置 bufferLogs: true ,也就是将日志缓存起来,并可以传给自定义的 logger ,也就是使用 useLogger 指定了 logger 并且等待应用初始化完毕即可。
async function bootstrap() {
const app = await NestFactory.create(AppModule, {
bufferLogs: true,
});
app.useLogger(app.get(MyLogger3));
await app.listen(3000);
}
我们新建 MyLogger3.ts 文件,定义装饰器 MyLogger3 继承了 ConsoleLogger 类。
添加 @Injectable() 装饰器,表明这是一个 provider,需要在 Module 里引入;并通过 @Inject 注入 AppService,并在 log 方法中进行调用。
import { ConsoleLogger, Injectable, Inject } 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('--------------');
}
}
pnpm start 运行项目,可以观察到打印的日志为:
Hello World!
[NestFactory] Starting Nest application...
--------------
Hello World!
[InstanceLoader] AppModule dependencies initialized
--------------
Hello World!
[RoutesResolver] AppController {/}:
--------------
Hello World!
[RouterExplorer] Mapped {/, GET} route
--------------
Hello World!
[NestApplication] Nest application successfully started
--------------
也就是说,依赖注入成功实现了。
后记
总的来说,Nest 中的日志打印可以指定 logger 是否开启、指定打印的日志级别、自定义 logger 等。
在本文中,我们探索了 Logger 类、LoggerService 接口,以及通过继承 ConsoleLogger 以实现自定义的 logger 等。此外,我们还学习了如何实现依赖注入的方法。
在 Nest 后端应用中,学会打印和查看日志也是掌握 Nest 的很重要的一环。