logger 是 nestjs 内置的功能。看看怎么使用,以及如何自定义 logger。
开启/关闭 logger 的显示
- 我们在创建一个 app 的时候,我们就可在 create 参数添加第二参数,来配置 logger
const app = await NestFactory.create(ApplicationModule, {
logger: false,
});
await app.listen(3000);
源码:
public async create<T extends INestApplication = INestApplication>(
module: any,
serverOrOptions?: AbstractHttpAdapter | NestApplicationOptions,
options?: NestApplicationOptions,
): Promise<T> {}
- NestApplicationOptions 继承子 NestApplicationContextOptions
export class NestApplicationContextOptions {
logger?: LoggerService | LogLevel[] | boolean;
}
logger 级别:
- 'log'
- 'error'
- 'warn'
- 'debug'
- 'verbose'。
// 层次类型
export type LogLevel = 'log' | 'error' | 'warn' | 'debug' | 'verbose';
// 创建app时使用配置 logger 层次
const app = await NestFactory.create(ApplicationModule, {
logger: ['error', 'warn'],
});
await app.listen(3000);
LoggerService 接口
我们要实现自定Logger必须实现 LoggerService
export interface LoggerService {
log(message: any, context?: string);
error(message: any, trace?: string, context?: string);
warn(message: any, context?: string);
debug?(message: any, context?: string);
verbose?(message: any, context?: string);
}
import { LoggerService } from '@nestjs/common';
export class MyLogger implements LoggerService {
log(message: string) {}
error(message: string, trace: string) {}
warn(message: string) {}
debug(message: string) {}
verbose(message: string) {}
}
扩展现有 logger
扩展 nestjs 的 logger 需要继承 nestjs 的 Logger 接口,而 Logger 是继承上面的 LoggerService 接口
import { Logger } from '@nestjs/common';
export class MyLogger extends Logger {
error(message: string, trace: string) {
super.error(message, trace);
}
}
源码
@Injectable()
export class Logger implements LoggerService {
private static logLevels: LogLevel[] = [
'log',
'error',
'warn',
'debug',
'verbose',
];
private static lastTimestamp?: number;
private static instance?: typeof Logger | LoggerService = Logger;
constructor(
@Optional() protected context?: string,
@Optional() private readonly isTimestampEnabled = false,
) {}
error(message: any, trace = '', context?: string) {}
log(message: any, context?: string) {}
warn(message: any, context?: string) {}
debug(message: any, context?: string) {}
verbose(message: any, context?: string) {}
setContext(context: string) {}
static overrideLogger(logger: LoggerService | LogLevel[] | boolean) {}
static log(message: any, context = '', isTimeDiffEnabled = true) {}
static error(
message: any,
trace = '',
context = '',
isTimeDiffEnabled = true,
) {}
static warn(message: any, context = '', isTimeDiffEnabled = true) {}
static debug(message: any, context = '', isTimeDiffEnabled = true) {}
static verbose(message: any, context = '', isTimeDiffEnabled = true) {}
private callFunction(
name: 'log' | 'warn' | 'debug' | 'verbose',
message: any,
context?: string,
) {}
private getInstance(): typeof Logger | LoggerService {}
private isLogLevelEnabled(level: LogLevel): boolean {}
private static printMessage(
message: any,
color: (message: string) => string,
context = '',
isTimeDiffEnabled?: boolean,
) {}
private static updateAndGetTimestampDiff(
isTimeDiffEnabled?: boolean,
): string {}
private static printStackTrace(trace: string) {}
}
logger模块
import { Module } from '@nestjs/common';
import { MyLogger } from './my-logger.service';
@Module({
providers: [MyLogger],
exports: [MyLogger],
})
export class LoggerModule {}
同归依赖注入将 LoggerModule 注入都 AppModule 中,通过 app 的 get 方法来获取 MyLogger 的实例。app 也提供了 useLogger 来使用 Logger。
const app = await NestFactory.create(ApplicationModule, {
// 关闭系统日志
logger: false,
});
app.useLogger(app.get(MyLogger))
await app.listen(3000);
这看起来似乎有点麻烦,其实我们可以直接创新一个实例,不使用 Module 的方式来注入。
const app = await NestFactory.create(ApplicationModule, {
// 关闭系统日志
logger: false,
});
// 使用自定义日志
app.useLogger(new MyLogger());
await app.listen(3000);
通过将scope属性传递给@Injectable()装饰器选项对象来指定注入范围
Scope 是枚举类型
export enum Scope {
/**
* 提供程序可以在多个类之间共享。提供者生命周期
*与应用程序生命周期严格相关。一旦应用程序具有
*自举,所有提供程序都已实例化。
*/
DEFAULT,
/**
* 每次使用都会实例化提供者的新私有实例。
*/
TRANSIENT,
/**
* 为每个请求处理管道实例化一个新实例
*/
REQUEST,
}
// scope选项作为Logger类的配置元数据,并指定一个临时范围,
// 以确保Logger在每个功能模块中都有一个唯一的实例
import { Injectable, Scope, Logger } from '@nestjs/common';
@Injectable({ scope: Scope.TRANSIENT })
export class MyLogger extends Logger {}
import { Module } from '@nestjs/common';
import { MyLogger } from './my-logger.service';
@Module({
providers: [MyLogger],
exports: [MyLogger],
})
export class LoggerModule {}
import { Injectable } from '@nestjs/common';
import { MyLogger } from './my-logger.service';
@Injectable()
export class CatsService {
private readonly cats: Cat[] = [];
constructor(private myLogger: MyLogger) {
this.myLogger.setContext('CatsService');
}
findAll(): Cat[] {
this.myLogger.warn('About to return cats!');
return this.cats;
}
}
const app = await NestFactory.create(ApplicationModule, {
logger: false,
});
app.useLogger(new MyLogger());
await app.listen(3000);
使用作用域注入,可以每个模块中都包含一个 logger 实例,我们通过需要定义个单独的 Module 模块。在使用的的时候,我们在服务中使用 MyLogger。最后我们还需要在 app 需要调用 useLogger 来实例化 MyLogger 函数。
第三方 logger
生产应用程序通常具有特定的日志记录要求,包括高级筛选,格式化和集中式日志记录。Nest的内置记录器用于监视Nest系统的行为,并且在开发过程中也可用于功能模块中的基本格式化文本记录,但是生产应用程序通常会利用Winston等专用记录模块。与任何标准Node.js应用程序一样,您可以在Nest中充分利用此类模块。