温馨提示×

Node.js日志轮转是如何实现的

小樊
37
2025-12-24 06:22:48
栏目: 编程语言

Node.js日志轮转的实现方式

一 核心原理

  • 基于时间的切割:按小时/天/周等时间粒度创建新文件,常见做法是把时间戳嵌入文件名(如 application-2025-09-01.log),便于检索与归档。
  • 基于大小的切割:当单文件达到阈值(如10 MB、100 MB)时触发轮转,通常按序号或时间重命名旧文件,并创建新文件继续写入。
  • 保留与压缩:配合保留策略(如保留7天/14个文件)与压缩归档,控制磁盘占用并提升历史日志查询效率。
  • 触发与执行:应用内由日志库的传输层(Transport)在写入时检测并轮转;系统级通过logrotate在外部定时轮转;容器环境可通过Docker 日志驱动限制容器日志大小与数量。
  • 可靠性要点:轮转时要确保文件句柄安全切换、避免丢日志;写入异常要可降级(如回退到控制台/备用路径);对外部系统尽量使用固定文件名或稳定通配符,便于采集器读取。

二 常用实现方案

  • 应用内方案
    • Winston + winston-daily-rotate-file:支持按时间/大小切割、压缩过期清理,适合需要细粒度控制格式与策略的场景。
    • Pino:高性能,配合 pino-rotate 等插件实现按时间/大小轮转。
    • Log4js:内置按日期切割与保留天数、压缩等能力,配置简单。
  • 系统级方案
    • Linux logrotate:对指定路径日志执行轮转、压缩、删除,配置灵活,适合不改代码统一管理多进程/多应用日志。
  • 进程管理/容器方案
    • PM2:内置日志轮转参数(如 max_size、max_files),零代码侵入,适合快速上线。
    • Docker:使用 local 日志驱动并设置 max-size / max-file,由容器运行时管理日志文件。

三 代码示例

  • Winston 按天轮转并压缩(保留14天)
const winston = require('winston');
const DailyRotateFile = require('winston-daily-rotate-file');

const transport = new DailyRotateFile({
  filename: 'logs/app-%DATE%.log',   // 文件名含日期占位符
  datePattern: 'YYYY-MM-DD',         // 按天切割
  zippedArchive: true,              // 旧日志压缩
  maxSize: '20m',                   // 单个文件上限
  maxFiles: '14d'                   // 保留14天
});

const logger = winston.createLogger({
  level: 'info',
  format: winston.format.json(),
  transports: [transport]
});

logger.info('hello, winston rotate');
  • 固定文件名、大小触发的循环覆盖(适合采集器要求固定路径)
const winston = require('winston');

const logger = winston.createLogger({
  level: 'debug',
  transports: [
    new winston.transports.File({
      filename: 'logs/service.log', // 固定文件名
      maxsize: 10 * 1024 * 1024,   // 10 MB
      maxFiles: 1,                 // 只保留1个文件
      rotationFormat: () => ''     // 轮转后不更改文件名,实现覆盖
    }),
    new winston.transports.Console({ level: 'info' })
  ],
  exitOnError: false
});
  • Linux logrotate 配置示例(系统级轮转)
/path/to/nodejs/logs/*.log {
    daily
    rotate 7
    compress
    missingok
    notifempty
    create 0644 root root
}
  • PM2 内置日志轮转(零代码侵入)
{
  "apps": [{
    "name": "my-api",
    "script": "src/index.js",
    "out_file": "./logs/out.log",
    "error_file": "./logs/err.log",
    "max_size": "20M",
    "max_files": "14"
  }]
}
  • Docker 日志驱动(容器运行时轮转)
docker run -d \
  --name my_app \
  --log-driver local \
  --log-opt max-size=10m \
  --log-opt max-file=3 \
  my_image

上述示例覆盖了应用内(Winston/Pino/Log4js)、系统级(logrotate)、进程管理(PM2)与容器(Docker)的主流做法。

四 选型与最佳实践

  • 何时选哪种方案
    • 需要自定义格式/多目标输出/复杂策略:优先用Winston/Pino/Log4js在应用内实现。
    • 多应用统一运维、不改代码:用logrotate
    • 快速上线、容器化部署:用PM2Docker 日志驱动
  • 关键配置建议
    • 同时设置时间+大小双阈值,避免单维度触发过于频繁或过大。
    • 开启压缩保留天数/个数,防止磁盘被历史日志撑爆。
    • 生产环境避免仅输出到单一文件,建议控制台+文件双写,便于本地排查与集中采集。
    • 容器与采集器场景尽量使用固定文件名或稳定通配符,减少符号链接与重命名带来的兼容问题。
    • 对高并发写入场景,优先选择异步、批量写入与合适的缓冲策略,降低 I/O 抖动。

0