老旧Node.js应用基于forever-monitor的12小时日志轮转方案咨询
Hey there! 针对你用forever-monitor管理老旧Node.js应用子进程日志、需要每12小时自动轮转归档的需求,我给你整理了几个Node.js生态里常用且靠谱的npm库,还有具体的实现思路,帮你避开依赖系统logrotate的麻烦:
推荐的Node.js日志轮转方案
1. rotating-file-stream(最推荐,轻量专注轮转)
这个库是专门做日志轮转的轻量工具,完全贴合你不想依赖系统工具的需求,用起来也很直接。它可以直接接管forever-monitor的日志输出流,自动完成每12小时的归档、重命名和清空操作。
具体实现步骤:
- 先安装库:
npm install rotating-file-stream - 配置轮转流,指定归档目录和带时间戳的文件名规则:
const rfs = require('rotating-file-stream'); const path = require('path'); const fs = require('fs'); // 确保归档目录存在,不存在就创建 const archiveDir = path.join(__dirname, '../logs/archives'); fs.mkdirSync(archiveDir, { recursive: true }); // 生成带时间戳的归档文件名 const getOutputFilename = (time) => { if (!time) return 'childprocess_output.log'; // 当前活跃的日志文件名 const timestamp = time.getTime(); return `childprocess_output_${timestamp}.log`; }; // 创建输出日志的轮转流:每12小时轮转,归档到指定目录 const outStream = rfs.createStream(getOutputFilename, { interval: '12h', // 轮转间隔设为12小时 path: archiveDir, size: '0', // 只按时间轮转,忽略文件大小 compress: false, // 需要压缩归档文件的话可以改成'gzip' maxFiles: 0, // 0表示不限制归档文件数量,按需调整 initialRotation: false // 启动时不立即触发轮转 }); // 同样配置错误日志的轮转流 const getErrFilename = (time) => { if (!time) return 'childprocess_error.log'; const timestamp = time.getTime(); return `childprocess_error_${timestamp}.log`; }; const errStream = rfs.createStream(getErrFilename, { interval: '12h', path: archiveDir, size: '0' }); - 修改forever-monitor的配置,把子进程的输出导向我们的轮转流:
const forever = require('forever-monitor'); var child = new (forever.Monitor)(__dirname + '/../lib/childprocess.js', { max: 3, silent: false, // 关闭forever自带的文件写入,我们自己处理流 options: [program.port] }); // 把子进程的标准输出和错误输出分别导向轮转流 child.stdout.pipe(outStream); child.stderr.pipe(errStream); child.start();
这样配置后,每12小时库会自动把当前的childprocess_output.log归档到archives目录,重命名为带时间戳的文件,然后创建新的空日志文件继续写入,完全符合你的需求。
2. winston + winston-daily-rotate-file(适合需要扩展日志功能的场景)
如果你的应用未来可能需要更复杂的日志处理(比如分级别日志、多输出目标),可以用Winston这个成熟的日志框架,搭配它的winston-daily-rotate-file插件,支持按时间、大小轮转,还能自定义文件名格式。
实现思路:
- 安装依赖:
npm install winston winston-daily-rotate-file - 配置Winston日志实例,设置轮转规则:
const winston = require('winston'); const { DailyRotateFile } = require('winston-daily-rotate-file'); const path = require('path'); const fs = require('fs'); const archiveDir = path.join(__dirname, '../logs/archives'); fs.mkdirSync(archiveDir, { recursive: true }); // 配置输出日志的轮转transport const outputLogger = winston.createLogger({ transports: [ new DailyRotateFile({ filename: 'childprocess_output_%TIMESTAMP%.log', datePattern: 'YYYY-MM-DD_HH', // 按小时区分,适配12小时轮转 frequency: '12h', // 每12小时轮转一次 maxFiles: '30d', // 保留30天的归档日志,按需调整 dirname: archiveDir, createSymlink: true, symlinkName: path.join(__dirname, '../childprocess_output.log') // 软链接指向当前活跃日志 }) ] }); // 同样配置错误日志的轮转transport const errorLogger = winston.createLogger({ transports: [ new DailyRotateFile({ filename: 'childprocess_error_%TIMESTAMP%.log', datePattern: 'YYYY-MM-DD_HH', frequency: '12h', maxFiles: '30d', dirname: archiveDir, createSymlink: true, symlinkName: path.join(__dirname, '../childprocess_error.log') }) ] }); - 把forever子进程的输出传给Winston处理:
var child = new (forever.Monitor)(__dirname + '/../lib/childprocess.js', { max: 3, silent: false, options: [program.port] }); // 监听子进程输出,写入Winston日志 child.stdout.on('data', (data) => { outputLogger.info(data.toString().trim()); }); child.stderr.on('data', (data) => { errorLogger.error(data.toString().trim()); }); child.start();
这种方式的好处是Winston提供了更多日志处理能力,比如日志级别、格式化等,但比单纯的轮转库稍重,适合需要扩展日志功能的场景。
3. logrotate-stream(轻量流式轮转备选)
这个库也是专注于流式日志轮转,用法简洁,支持按时间或大小轮转,适合追求轻量的场景。
简单示例:
const logrotate = require('logrotate-stream'); const path = require('path'); const fs = require('fs'); const archiveDir = path.join(__dirname, '../logs/archives'); fs.mkdirSync(archiveDir, { recursive: true }); // 创建输出日志的轮转流 const outStream = logrotate({ file: path.join(__dirname, '../childprocess_output.log'), rotate: '12h', size: '0', // 禁用按大小轮转 keep: 0, // 保留所有归档文件 compress: false, // 自定义归档文件名和路径 rename: (filename) => { const timestamp = Date.now(); return path.join(archiveDir, `childprocess_output_${timestamp}.log`); } }); // 同样配置错误日志流,然后pipe到forever的输出 child.stdout.pipe(outStream);
一些注意事项
- 无论用哪个库,都要确保归档目录存在,可以用
fs.mkdirSync(archiveDir, { recursive: true })在启动时自动创建,避免报错。 - 测试的时候可以把轮转间隔改成
1m(1分钟),快速验证功能是否正常。 - 如果你的forever-monitor版本比较老,要确认它的
stdout和stderr流可以正常被pipe,个别老版本可能需要微调配置。
内容的提问来源于stack exchange,提问作者Rito
相关产品推荐
相关产品推荐

