在NestJS中,nest-winston
包用于集成 Winston 日志库,以便更好地进行日志记录。以下是如何使用 nest-winston
包的基本步骤和一些配置选项:
1.安装依赖:
首先,你需要安装 nest-winston
和 winston
包。你可以使用 pnpm 或 yarn 来安装这些依赖。
pnpm install nest-winston winston
安装winston-daily-rotate-file使日志可以本地按天轮转
pnpm install winston-daily-rotate-file
2.配置 WinstonModule:
在 AppModule
中配置 WinstonModule
。下面是一个示例配置:
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { utilities as nestWinstonModuleUtilities, WinstonModule } from 'nest-winston';
import * as winston from 'winston';
import 'winston-daily-rotate-file';
@Module({
imports: [
WinstonModule.forRoot({
transports: [
new winston.transports.Console({
// 结合多个格式化器来定义控制台日志的输出格式
format: winston.format.combine(
// 添加时间戳到日志中
winston.format.timestamp(),
// 添加毫秒数到日志中
winston.format.ms(),
// 使用 nest-winston 提供的 nestLike 格式化器,使日志更符合 NestJS 的风格
nestWinstonModuleUtilities.format.nestLike('NestjsFrame', {
colors: true, // 使用颜色来区分不同的日志级别
prettyPrint: true, // 以更易读的格式打印日志
processId: true, // 添加进程 ID 到日志中
appName: true, // 添加应用名称到日志中
}),
),
}),
new winston.transports.DailyRotateFile({
dirname: 'logs', // 日志文件存储的目录
level: 'info', // 记录 info 级别及以上的日志
filename: 'NestjsFrame-%DATE%.log', // 日志文件名格式,%DATE% 会被替换为日期
datePattern: 'YYYY-MM-DD-HH', // 日期格式,用于生成日志文件名中的日期部分
zippedArchive: true, // 是否将旧的日志文件压缩
maxSize: '20m', // 单个日志文件的最大大小,超过这个大小会创建新的日志文件
maxFiles: '14d', // 保留日志文件的最大天数
// 结合多个格式化器来定义文件日志的输出格式
format: winston.format.combine(
// 添加时间戳到日志中
winston.format.timestamp(),
// 使用简单的格式化器
winston.format.simple(),
),
}),
],
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
3.使用日志服务:
在你的服务或控制器中注入 @Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger
并使用它来记录日志。
import { Controller, Get, Inject } from '@nestjs/common';
import { AppService } from './app.service';
import { WINSTON_MODULE_PROVIDER } from 'nest-winston'
import { Logger } from 'winston';
@Controller()
export class AppController {
constructor(
private readonly appService: AppService,
@Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger
) { }
@Get()
getHello(): string {
this.logger.info('Hello World!', AppController.name);
this.logger.warn('Hello World!', AppController.name);
this.logger.error('Hello World!', AppController.name);
return this.appService.getHello();
}
}
4.推荐的用法:
在 main.ts
中使用 useLogger
更换默认日志记录器,这样我们在使用的时可以直接使用 NestJS
内置的 Logger
就可以。
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston';
import { HttpFilter } from './http.filter';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useLogger(app.get(WINSTON_MODULE_NEST_PROVIDER));
app.useGlobalFilters(new HttpFilter())
await app.listen(process.env.PORT ?? 3000);
}
bootstrap();
在某个业务或者控制器使用Logger:从'@nestjs/common'
引入new一个即可。
import { Injectable, Logger } from '@nestjs/common';
@Injectable()
export class UserService {
private logger = new Logger('UserService');
async create(createUserDto: CreateUserDto) {
this.logger.log('@@@@ 创建用户参数:', createUserDto);
// ...业务逻辑
}
async findAll(query: ListUserDto) {
try {
// ...业务逻辑
} catch (error) {
this.logger.error('@@@@ 账号列表查询失败:', error);
throw new InternalServerErrorException('账号列表查询失败');
}
}
}
通过以上步骤,你可以在 NestJS 应用中使用 nest-winston
包来记录日志。根据你的需求,你可以进一步自定义日志的格式、输出位置和级别。
5.优化一下:
AppModule
里winston配置一大坨,并不美观,抽离一下,新建logger.config.ts
import { createLogger, format } from 'winston';
import { utilities as nestWinstonModuleUtilities } from 'nest-winston';
import 'winston-daily-rotate-file';
import * as winston from 'winston';
const winstonLogger = createLogger({
format: format.combine(
format.timestamp(),
format.errors({ stack: true }),
format.splat(),
format.json(),
),
defaultMeta: { service: 'log-service' },
transports: [
new winston.transports.DailyRotateFile({
dirname: 'logs/info', // 日志文件存储的目录
level: 'info', // 记录 info 级别及以上的日志
filename: 'info-%DATE%.log', // 日志文件名格式,%DATE% 会被替换为日期
datePattern: 'YYYY-MM-DD-HH', // 日期格式,用于生成日志文件名中的日期部分
zippedArchive: true, // 是否将旧的日志文件压缩
maxSize: '20m', // 单个日志文件的最大大小,超过这个大小会创建新的日志文件
maxFiles: '14d', // 保留日志文件的最大天数
// 结合多个格式化器来定义文件日志的输出格式
format: winston.format.combine(
// 添加时间戳到日志中
winston.format.timestamp(),
// 使用简单的格式化器
winston.format.simple(),
),
}),
new winston.transports.DailyRotateFile({
dirname: 'logs/error',
level: 'error',
filename: 'error-%DATE%.log',
datePattern: 'YYYY-MM-DD-HH',
zippedArchive: true,
maxSize: '20m',
maxFiles: '14d',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.simple(),
),
}),
new winston.transports.DailyRotateFile({
dirname: 'logs/warn',
level: 'warn',
filename: 'warn-%DATE%.log',
datePattern: 'YYYY-MM-DD-HH',
zippedArchive: true,
maxSize: '20m',
maxFiles: '14d',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.simple(),
),
}),
new winston.transports.Console({
// 结合多个格式化器来定义控制台日志的输出格式
format: winston.format.combine(
winston.format.timestamp(),
winston.format.ms(),
// 使用 nest-winston 提供的 nestLike 格式化器,使日志更符合 NestJS 的风格
nestWinstonModuleUtilities.format.nestLike('NestjsFrame', {
colors: true, // 使用颜色来区分不同的日志级别
prettyPrint: true, // 以更易读的格式打印日志
processId: true, // 添加进程 ID 到日志中
appName: true, // 添加应用名称到日志中
}),
),
}),
],
});
export default winstonLogger;
优化后的AppModule
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { WinstonModule } from 'nest-winston';
import winstonLogger from './config/logger.config';
@Module({
imports: [WinstonModule.forRoot({
transports: winstonLogger.transports,
format: winstonLogger.format,
defaultMeta: winstonLogger.defaultMeta,
exitOnError: false,
}),],
controllers: [AppController],
providers: [AppService],
})
export class AppModule { }