NestJS 日志轮转实战:winston-daily-rotate-file 详解与避坑指南
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!如果不进行轮转,会有什么后果?
- 磁盘空间爆炸:硬盘空间被日志文件占满,导致应用无法正常运行。
- 性能下降:写入巨大的日志文件会消耗大量的 I/O 资源,影响应用的响应速度。
- 难以排查问题:在巨大的日志文件中查找特定信息,无异于大海捞针。
- 数据丢失风险:如果日志文件损坏,可能会丢失大量的日志数据。
日志轮转可以将日志文件按照时间(例如每天、每小时)或大小进行分割,并自动删除旧的日志文件,从而避免上述问题。它就像一个勤劳的园丁,定期修剪你的日志“花园”,保持整洁和健康。
winston-daily-rotate-file
简介
winston-daily-rotate-file
是 winston
的一个 transport(传输器),专门用于实现基于时间和日期的日志轮转。它提供了丰富的配置选项,可以满足各种场景下的日志管理需求。
主要特性:
- 按时间轮转:可以按照每天、每小时、每分钟甚至每秒进行日志轮转。
- 按大小轮转: 当日志文件大小超过设定大小,就触发日志轮转
- 自动删除旧日志:可以设置保留的日志文件数量或保留时间,自动删除过期的日志文件。
- 压缩归档:可以将旧的日志文件压缩成
.gz
格式,节省磁盘空间。 - 自定义文件名:可以自定义日志文件的命名格式,方便识别和管理。
- 支持多种日期格式: 可以灵活定义日期格式
实战:在 NestJS 中集成 winston-daily-rotate-file
接下来,咱们就一步步地在 NestJS 项目中集成 winston-daily-rotate-file
。
1. 安装依赖
首先,你需要安装 winston
和 winston-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
的过程中,可能会遇到一些问题。下面是一些常见问题和解决方案:
- 日志文件没有按预期轮转:
- 检查
datePattern
是否正确设置。 - 确保应用有足够的权限创建和写入日志文件。
- 如果使用了 PM2 等进程管理器,可能需要配置 PM2 的日志轮转。
- 检查
- 旧日志文件没有被删除:
- 检查
maxFiles
是否正确设置。 - 确保应用有足够的权限删除旧的日志文件。
- 检查
- 日志文件过大:
- 除了按时间轮转,还可以配置按大小轮转,设置
maxSize
- 调整
datePattern
,例如从每天轮转改为每小时轮转。 - 考虑使用更高效的日志格式,例如 JSON。
- 如果某些日志信息不重要,可以考虑降低日志级别或过滤掉这些日志。
- 除了按时间轮转,还可以配置按大小轮转,设置
- 日志文件编码问题:
- 确保在创建
DailyRotateFile
实例时设置了正确的编码,例如options.encoding = 'utf8'
。
- 确保在创建
- 并发写入问题
- 在高并发场景下, 多个进程同时写入同一个日志文件,可能会有冲突. 可以考虑给每个进程的日志文件增加PID后缀来规避:
new DailyRotateFile({ filename: `logs/application-%DATE%-${process.pid}.log`, // ...其他配置 })
- 时区问题
- 默认情况下,
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
等. 不同的库有不同的特点和适用场景, 你可以根据自己的需求选择合适的库. 最重要的是理解日志轮转的原理和最佳实践, 这样才能更好地管理你的应用日志。
如果你在实践中遇到任何问题,或者有更好的建议,欢迎在评论区留言交流!