主题
nest 记录日志
前言
作为服务端应用,有一个完善的日志系统非常有必要,日志是用于排查解决问题的依据,我们平时开发中经常使用console.log
来打印日志信息,非常方便,但是它在终端关闭后就没了,nest 考虑到这一点,也提供了一套解决方案。
nest 默认的日志
用nest-cli创建一个新项目
sh
nest new nest-log-demo -p pnpm
提示
-p
是 --package-manager
的别名,表示指定包管理器。使用 npm 、 yarn 或 pnpm 。包管理器必须全局安装。
然后启动项目pnpm run start:dev
,能看到 nest 默认打印的几行日志
使用 nest 默认的日志来打印日志
nest 内置了日志打印功能,可以在需要打印日志的地方直接使用,例如:controller service
ts
import { Controller, Get, Logger } from "@nestjs/common";
import { AppService } from "./app.service";
@Controller()
export class AppController {
logger: Logger;
constructor(private readonly appService: AppService) {
this.logger = new Logger(AppController.name);
}
@Get()
getHello(): string {
this.logger.log("aaaaaaaaaa");
this.logger.debug("aaaaaaaaaa");
this.logger.error("aaaaaaaaaa");
this.logger.fatal("aaaaaaaaaa");
this.logger.verbose("aaaaaaaaaa");
this.logger.warn("aaaaaaaaaa");
return this.appService.getHello();
}
}
效果如下:
log
debug
等表示日志级别
这个日志是受 Nest 控制的,可以在创建应用的时候指定是否开启:
ts
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();
关闭后的效果:
自定义日志打印
- 实现 LoggerService 接口
除了上面的直接使用 nest 内置 logger 来打印日志之外,还可以自定义日志打印的方式,定义一个实现 LoggerService 接口的类
ts
// src/myLogger.ts
import { LoggerService } from "@nestjs/common";
// MyLogger 必须实现 log warn error三个方法
export class MyLogger implements LoggerService {
log(message: string, context?: string) {
console.log(`---log---[${context}]---`, message);
}
warn(message: string, context?: string) {
console.log(`---warn---[${context}]---`, message);
}
error(message: string, context?: string) {
console.log(`---error---[${context}]---`, message);
}
}
在创建应用时指定这个 logger
ts
// main.ts
import { NestFactory } from "@nestjs/core";
import { AppModule } from "./app.module";
import { MyLogger } from "./myLogger";
async function bootstrap() {
const app = await NestFactory.create(AppModule, {
logger: new MyLogger(),
});
await app.listen(3000);
}
bootstrap();
效果:
- 继承 LoggerService
你也可以不自己实现 LoggerService 的全部方法,而是继承 ConsoleLogger,重写一些方法:
ts
import { ConsoleLogger } from "@nestjs/common";
export class MyLogger extends ConsoleLogger {
log(message: string, context: string) {
console.log(`[${context}]`, message);
}
}
因为 ConsoleLogger 实现了 LoggerService 接口,这样我们没重写的方法就是原来的:
Logger 依赖注入
上述的日志打印可以正常使用,但是没办法实现依赖注入,因为 Logger 是在容器外面手动 new 的对象,接下来对其进行改造
先给 MyLogger
添加 @Injectable()
装饰器,代表这是一个 provider
, 可以注入和被注入。 !
假如要注入到 appService 里面, 需要再 appModule 内 providers 注册一下,然后再在 appSercice 里面 Inject 一下;
最后改造入口
提示
bufferLogs 就是先不打印日志,把它放到 buffer 缓冲区,直到用 useLogger 指定了 Logger 并且应用初始化完毕。
app.get 就是从容器中取这个类的实例的
现在打印的日志长这样 很明显,已经成功注入 appService
设置成模块
也可以单独将日志模块弄成一个当独的模块,例如全局模块和动态模块
- 动态模块,每次 imports 的时候配置下
ts
import { DynamicModule, Global, Module } from "@nestjs/common";
import { MyLogger } from "./MyLogger";
@Module({})
export class LoggerModule {
static register(options): DynamicModule {
return {
module: LoggerModule,
providers: [
MyLogger,
{
provide: "LOG_OPTIONS",
useValue: options,
},
],
exports: [MyLogger, "LOG_OPTIONS"],
};
}
}
每次 imports 的时候传入不同的配置:
在 AppService 里注入下:
ts
import { Inject, Injectable } from "@nestjs/common";
import { MyLogger } from "./logger2/MyLogger";
@Injectable()
export class AppService {
@Inject(MyLogger)
private logger: MyLogger;
getHello(): string {
this.logger.log("yyy", AppService.name);
return "Hello World!";
}
}
小结
日志打印可以用 Nest 的 Logger,它支持在创建应用的时候指定 logger 是否开启,打印的日志级别,还可以自定义 logger。
自定义 Logger 需要实现 LoggerService 接口,或者继承 ConsoleLogger 然后重写部分方法。
如果想在 Logger 注入一些 provider,就需要创建应用时设置 bufferLogs 为 true,然后用 app.useLogger(app.get(xxxLogger)) 来指定 Logger。
你可以把这个自定义 Logger 封装到全局模块,或者动态模块里。
当然,一般情况下,直接使用 Logger 就可以了。