WEBKT

NestJS 日志轮转实战:winston-daily-rotate-file 详解与避坑指南

33 0 0 0

NestJS 日志轮转实战:winston-daily-rotate-file 详解与避坑指南

为什么要进行日志轮转?

winston-daily-rotate-file 简介

实战:在 NestJS 中集成 winston-daily-rotate-file

1. 安装依赖

2. 创建 Winston Logger 实例

3. 在 AppModule 中导入 LoggerModule

4. 在服务中使用 Logger

常见问题与避坑指南

总结

NestJS 日志轮转实战:winston-daily-rotate-file 详解与避坑指南

你好!作为一名 NestJS 开发者,你肯定遇到过日志文件管理的问题。随着应用运行时间的增长,日志文件会越来越大,不仅占用磁盘空间,还可能影响应用的性能。更重要的是,当排查问题时,面对一个巨大的日志文件,简直就是大海捞针!

这时候,日志轮转就显得尤为重要了。今天,咱们就来聊聊如何在 NestJS 项目中,通过 winston-daily-rotate-file 这个库实现日志轮转,让你的日志管理更轻松、更高效。

为什么要进行日志轮转?

在深入讲解 winston-daily-rotate-file 之前,咱们先来明确一下日志轮转的重要性。想象一下,如果你的应用每天产生 1GB 的日志,一个月下来就是 30GB!如果不进行轮转,会有什么后果?

  1. 磁盘空间爆炸:硬盘空间被日志文件占满,导致应用无法正常运行。
  2. 性能下降:写入巨大的日志文件会消耗大量的 I/O 资源,影响应用的响应速度。
  3. 难以排查问题:在巨大的日志文件中查找特定信息,无异于大海捞针。
  4. 数据丢失风险:如果日志文件损坏,可能会丢失大量的日志数据。

日志轮转可以将日志文件按照时间(例如每天、每小时)或大小进行分割,并自动删除旧的日志文件,从而避免上述问题。它就像一个勤劳的园丁,定期修剪你的日志“花园”,保持整洁和健康。

winston-daily-rotate-file 简介

winston-daily-rotate-filewinston 的一个 transport(传输器),专门用于实现基于时间和日期的日志轮转。它提供了丰富的配置选项,可以满足各种场景下的日志管理需求。

主要特性:

  • 按时间轮转:可以按照每天、每小时、每分钟甚至每秒进行日志轮转。
  • 按大小轮转: 当日志文件大小超过设定大小,就触发日志轮转
  • 自动删除旧日志:可以设置保留的日志文件数量或保留时间,自动删除过期的日志文件。
  • 压缩归档:可以将旧的日志文件压缩成 .gz 格式,节省磁盘空间。
  • 自定义文件名:可以自定义日志文件的命名格式,方便识别和管理。
  • 支持多种日期格式: 可以灵活定义日期格式

实战:在 NestJS 中集成 winston-daily-rotate-file

接下来,咱们就一步步地在 NestJS 项目中集成 winston-daily-rotate-file

1. 安装依赖

首先,你需要安装 winstonwinston-daily-rotate-file

npm install winston winston-daily-rotate-file

2. 创建 Winston Logger 实例

在 NestJS 中,通常会在一个单独的模块中配置 Winston Logger。创建一个 logger.module.ts 文件:

// logger.module.ts
import { Module } from '@nestjs/common';
import { LoggerModule as PinoLoggerModule } from 'nestjs-pino';
import * as winston from 'winston';
import * as DailyRotateFile from 'winston-daily-rotate-file';
@Module({
imports: [
PinoLoggerModule.forRoot({
pinoHttp: {
// base: null, // 禁用默认的 base 字段
// 禁用默认的请求日志记录
autoLogging: false,
// 使用 Winston 作为底层日志记录器
logger: winston.createLogger({
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [
new DailyRotateFile({
filename: 'logs/application-%DATE%.log', // 日志文件名格式
datePattern: 'YYYY-MM-DD-HH',
zippedArchive: true, // 是否压缩归档
maxSize: '20m', // 最大文件大小
maxFiles: '14d', // 最多保留 14 天的日志
}),
// 如果是开发环境,同时输出到控制台
...(process.env.NODE_ENV !== 'production'
? [new winston.transports.Console()]
: []),
],
}),
serializers: {
req(req) {
return {
method: req.method,
url: req.url,
query: req.query,
params: req.params,
headers: req.headers,
};
},
},
}
}),
],
})
export class LoggerModule {}

这里我们使用了nestjs-pino,它是一个基于pino的日志库,可以无缝集成winston. 上述代码创建了一个 Winston Logger 实例,并配置了一个 DailyRotateFile transport。其中:

  • filename: 日志文件的命名格式,%DATE% 会被替换成当前的日期。
  • datePattern: 日期格式,这里设置为 YYYY-MM-DD-HH,表示每小时创建一个新的日志文件。
  • zippedArchive: 是否压缩归档的日志文件。
  • maxSize: 每个日志文件的最大大小,这里设置为 20MB。
  • maxFiles: 最多保留的日志文件数量,这里设置为 14d,表示保留 14 天的日志。
  • winston.format.combine: 自定义日志输出格式,这里使用了时间戳以及JSON格式化
  • transports: 可以同时配置多个transports,例如这里还配置了Console transport,在开发环境会把日志同时输出到控制台
  • serializers: 自定义请求日志序列化,避免记录敏感信息,这里只记录了method,url,query等信息.

3. 在 AppModule 中导入 LoggerModule

// app.module.ts
import { Module } from '@nestjs/common';
import { LoggerModule } from './logger.module';
@Module({
imports: [LoggerModule],
})
export class AppModule {}

4. 在服务中使用 Logger

现在,你可以在任何服务中注入 Logger 实例,并使用它来记录日志:

// app.service.ts
import { Injectable, Logger } from '@nestjs/common';
import { InjectPinoLogger, PinoLogger } from 'nestjs-pino';
@Injectable()
export class AppService {
constructor(@InjectPinoLogger(AppService.name) private readonly logger: PinoLogger) {}
getHello(): string {
this.logger.info('Hello World!');
return 'Hello World!';
}
}

这里我们使用了@InjectPinoLogger装饰器注入Logger. 现在,当你调用 getHello() 方法时,就会在 logs 目录下生成一个类似 application-2023-10-27-10.log 的日志文件,其中包含了 Hello World! 这条日志信息。

常见问题与避坑指南

在使用 winston-daily-rotate-file 的过程中,可能会遇到一些问题。下面是一些常见问题和解决方案:

  1. 日志文件没有按预期轮转
    • 检查 datePattern 是否正确设置。
    • 确保应用有足够的权限创建和写入日志文件。
    • 如果使用了 PM2 等进程管理器,可能需要配置 PM2 的日志轮转。
  2. 旧日志文件没有被删除
    • 检查 maxFiles 是否正确设置。
    • 确保应用有足够的权限删除旧的日志文件。
  3. 日志文件过大
    • 除了按时间轮转,还可以配置按大小轮转,设置maxSize
    • 调整 datePattern,例如从每天轮转改为每小时轮转。
    • 考虑使用更高效的日志格式,例如 JSON。
    • 如果某些日志信息不重要,可以考虑降低日志级别或过滤掉这些日志。
  4. 日志文件编码问题
    • 确保在创建 DailyRotateFile 实例时设置了正确的编码,例如 options.encoding = 'utf8'
  5. 并发写入问题
    • 在高并发场景下, 多个进程同时写入同一个日志文件,可能会有冲突. 可以考虑给每个进程的日志文件增加PID后缀来规避:
new DailyRotateFile({
filename: `logs/application-%DATE%-${process.pid}.log`,
// ...其他配置
})
  1. 时区问题
    • 默认情况下,winston-daily-rotate-file使用本地时间. 如果你的服务器部署在不同的时区,可能会导致日志时间不一致. 可以通过localTime选项来使用本地时间, 或者通过utc选项来使用UTC时间:
new DailyRotateFile({
filename: 'logs/application-%DATE%.log',
datePattern: 'YYYY-MM-DD-HH',
localTime: true, // 使用本地时间
// 或
// utc: true, // 使用 UTC 时间
// ...其他配置
})

总结

日志轮转是日志管理的重要组成部分。通过 winston-daily-rotate-file,你可以轻松地在 NestJS 项目中实现日志轮转,避免日志文件无限增长带来的各种问题。希望这篇文章能帮助你更好地管理你的 NestJS 应用日志!

当然,除了winston-daily-rotate-file, 还有其他一些日志轮转的库,如log4js等. 不同的库有不同的特点和适用场景, 你可以根据自己的需求选择合适的库. 最重要的是理解日志轮转的原理和最佳实践, 这样才能更好地管理你的应用日志。

如果你在实践中遇到任何问题,或者有更好的建议,欢迎在评论区留言交流!

技术老兵 NestJS日志winston

评论点评

打赏赞助
sponsor

感谢您的支持让我们更好的前行

分享

QRcode

https://www.webkt.com/article/7881