NestJS 日志管理:winston-daily-rotate-file 实现日志按天滚动归档
NestJS 日志管理:winston-daily-rotate-file 实现日志按天滚动归档
为什么需要日志轮转?
准备工作:安装依赖
创建日志服务 (Logger Service)
代码解析
在其他模块中使用日志服务
测试日志记录
更多配置选项
处理未捕获的异常和 Promise 拒绝
总结
NestJS 日志管理:winston-daily-rotate-file 实现日志按天滚动归档
对于长期运行的 NestJS 应用,日志管理至关重要。一个好的日志系统不仅能帮助你快速定位问题,还能让你了解应用的运行状态。winston
是 Node.js 社区中最流行的日志库之一,而 winston-daily-rotate-file
则是 winston
的一个传输器(Transport),它可以实现日志文件按日期自动轮转,避免单个日志文件过大,方便日志归档和管理。这篇教程将详细介绍如何在 NestJS 中配置和使用 winston-daily-rotate-file
。
为什么需要日志轮转?
想象一下,你的应用每天产生大量的日志,如果不进行轮转,所有的日志都写入同一个文件,这个文件会越来越大,最终可能达到几个 GB 甚至几十 GB。这将带来以下问题:
- 难以打开和查看: 大文件打开速度慢,甚至可能导致编辑器崩溃。
- 难以检索: 在巨大的日志文件中查找特定信息如同大海捞针。
- 磁盘空间不足: 日志文件不断增长,最终可能耗尽磁盘空间。
- 难以归档和备份: 大文件备份和恢复都需要更长的时间。
winston-daily-rotate-file
通过每天(或每小时、每分钟等)创建一个新的日志文件来解决这些问题,旧的日志文件可以被压缩、归档或删除,保持日志目录的整洁。
准备工作:安装依赖
首先,确保你的 NestJS 项目已经创建。如果没有,可以使用 Nest CLI 创建一个新项目:
nest new my-nestjs-app cd my-nestjs-app
然后,安装 winston
和 winston-daily-rotate-file
:
npm install winston winston-daily-rotate-file
创建日志服务 (Logger Service)
在 NestJS 中,推荐的做法是创建一个自定义的日志服务,而不是直接在各个模块中使用 winston
。这样可以更好地控制日志配置,并方便后续的扩展和维护。
- 创建
logger.service.ts
文件:
// src/logger/logger.service.ts import { Injectable, LoggerService } from '@nestjs/common'; import * as winston from 'winston'; import 'winston-daily-rotate-file'; @Injectable() export class MyLogger implements LoggerService { private logger: winston.Logger; constructor() { this.logger = winston.createLogger({ level: 'info', // 默认日志级别 format: winston.format.combine( winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), // 添加时间戳 winston.format.printf(({ timestamp, level, message, context }) => { return `${timestamp} [${context}] ${level}: ${message}`; }) ), transports: [ new winston.transports.Console(), // 输出到控制台 new winston.transports.DailyRotateFile({ filename: 'logs/application-%DATE%.log', // 日志文件名,%DATE% 会被替换为日期 datePattern: 'YYYY-MM-DD', // 日期格式 zippedArchive: true, // 是否压缩归档的日志文件 maxSize: '20m', // 每个日志文件的最大大小 maxFiles: '14d', // 保留的日志文件数量(天数) format: winston.format.combine( winston.format.timestamp(), winston.format.json() ) }), ], }); } log(message: string, context?: string) { this.logger.log('info', message, { context }); } error(message: string, trace?: string, context?: string) { this.logger.error(message, { trace, context }); } warn(message: string, context?: string) { this.logger.warn(message, { context }); } debug?(message: string, context?: string) { this.logger.debug(message, { context }); } verbose?(message: string, context?: string) { this.logger.verbose(message, { context }); } }
- 创建
logger.module.ts
文件:
// src/logger/logger.module.ts import { Module } from '@nestjs/common'; import { MyLogger } from './logger.service'; @Module({ providers: [MyLogger], exports: [MyLogger], // 导出 LoggerService,以便其他模块使用 }) export class LoggerModule {}
代码解析
winston.createLogger()
: 创建winston
日志实例。level
: 设置日志级别。低于此级别的日志消息将被忽略。常见的日志级别有(从低到高):silly
、debug
、verbose
、info
、warn
、error
。format
: 定义日志消息的格式。这里使用了combine
方法组合了多个格式化器:winston.format.timestamp()
: 添加时间戳。winston.format.printf()
: 自定义输出格式。winston.format.json()
: 将日志消息格式化为 JSON。
transports
: 配置日志输出目标。这里配置了两个传输器:winston.transports.Console
: 将日志输出到控制台。winston.transports.DailyRotateFile
: 将日志写入按日期轮转的文件。filename
: 日志文件名。%DATE%
是一个占位符,会被替换为实际的日期。datePattern
: 日期格式,用于生成日志文件名。zippedArchive
: 是否压缩归档的日志文件(.gz
)。maxSize
: 每个日志文件的最大大小。超过这个大小后,会创建一个新的文件。maxFiles
: 最多保留多少个日志文件。超过这个数量后,旧的文件会被删除。
MyLogger
类实现了LoggerService
接口: NestJS 内置的日志接口,定义了log
、error
、warn
、debug
、verbose
等方法。
在其他模块中使用日志服务
- 在
AppModule
中导入LoggerModule
:
// src/app.module.ts import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { LoggerModule } from './logger/logger.module'; @Module({ imports: [LoggerModule], // 导入 LoggerModule controllers: [AppController], providers: [AppService], }) export class AppModule {}
- 在需要使用日志的模块中注入
MyLogger
:
// src/app.service.ts import { Injectable } from '@nestjs/common'; import { MyLogger } from './logger/logger.service'; @Injectable() export class AppService { constructor(private readonly logger: MyLogger) {} getHello(): string { this.logger.log('处理 getHello 请求', AppService.name); // 记录日志 return 'Hello World!'; } }
测试日志记录
启动你的 NestJS 应用:
npm run start:dev
访问你的应用(例如,http://localhost:3000
),然后在你的项目根目录下找到 logs
文件夹,你应该会看到类似 application-2023-10-27.log
这样的日志文件。
更多配置选项
winston-daily-rotate-file
提供了许多配置选项,可以根据你的需求进行调整。以下是一些常用的选项:
frequency
: 轮转频率。例如,'hourly'
表示每小时轮转一次,'daily'
表示每天轮转一次(默认值)。auditFile
: 审计文件的路径。审计文件包含有关日志文件轮转的信息,可以用于调试。utc
: 是否使用 UTC 时间。默认为false
,使用本地时间。extension
: 文件扩展名,默认为空。createSymlink
: 创建软连接,默认为false
。symlinkName
: 软连接名称, 默认为current.log
。
你可以在 winston-daily-rotate-file
的文档中找到完整的配置选项列表:https://github.com/winstonjs/winston-daily-rotate-file
处理未捕获的异常和 Promise 拒绝
为了确保应用在发生未捕获的异常或 Promise 拒绝时也能记录日志,你可以在 winston
中配置 exceptionHandlers
和 rejectionHandlers
:
// logger.service.ts import { Injectable, LoggerService } from '@nestjs/common'; import * as winston from 'winston'; import 'winston-daily-rotate-file'; @Injectable() export class MyLogger implements LoggerService { private logger: winston.Logger; constructor() { const dailyRotateFileTransport = new winston.transports.DailyRotateFile({ filename: 'logs/application-%DATE%.log', datePattern: 'YYYY-MM-DD', zippedArchive: true, maxSize: '20m', maxFiles: '14d', format: winston.format.combine( winston.format.timestamp(), winston.format.json() ) }); this.logger = winston.createLogger({ level: 'info', format: winston.format.combine( winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), winston.format.printf(({ timestamp, level, message, context, trace }) => { return `${timestamp} [${context}] ${level}: ${message} ${trace ? `\n${trace}` : ''}`; }) ), transports: [ new winston.transports.Console(), dailyRotateFileTransport ], exceptionHandlers: [ dailyRotateFileTransport, new winston.transports.Console() ], rejectionHandlers: [ dailyRotateFileTransport, new winston.transports.Console() ] }); } // ... 其他方法 ... }
总结
通过本教程,你学习了如何在 NestJS 中使用 winston-daily-rotate-file
实现日志的按天滚动归档。这对于长期运行的 NestJS 应用至关重要,可以有效避免单个日志文件过大,方便日志的查看、检索、归档和管理。记得根据你的实际需求调整配置选项,例如日志级别、轮转频率、文件大小限制等。一个良好的日志系统是应用稳定运行的基石,希望这篇教程能帮助你构建更健壮的 NestJS 应用!