日志轮转是管理应用程序日志的重要策略,可以防止日志文件无限增长占用磁盘空间。以下是几种在Node.js中实现日志轮转的方法:
对于生产环境,推荐使用系统级的logrotate工具:
# /etc/logrotate.d/your-node-app
/path/to/your/node/app/logs/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 0640 root root
sharedscripts
postrotate
kill -USR2 `cat /path/to/your/node/app.pid 2>/dev/null` 2>/dev/null || true
endscript
}
const winston = require('winston');
const { createLogger, format, transports } = winston;
const logger = createLogger({
format: format.combine(
format.timestamp(),
format.json()
),
transports: [
new transports.File({
filename: 'application.log',
maxsize: 5242880, // 5MB
maxFiles: 5,
tailable: true
})
]
});
const log4js = require('log4js');
log4js.configure({
appenders: {
file: {
type: 'file',
filename: 'application.log',
maxLogSize: 10485760, // 10MB
backups: 5, // 保留5个备份
compress: true // 压缩旧日志
}
},
categories: {
default: { appenders: ['file'], level: 'info' }
}
});
const logger = log4js.getLogger();
如果你使用PM2管理Node.js进程:
# 安装PM2日志轮转模块
pm2 install pm2-logrotate
# 配置轮转参数
pm2 set pm2-logrotate:max_size 10M # 单个日志文件最大10MB
pm2 set pm2-logrotate:retain 30 # 保留30个日志文件
pm2 set pm2-logrotate:compress true # 压缩旧日志
pm2 set pm2-logrotate:rotateInterval '0 0 * * *' # 每天午夜轮转
如果需要更精细的控制,可以编写自定义轮转脚本:
const fs = require('fs');
const path = require('path');
const zlib = require('zlib');
function rotateLog(logPath, maxFiles = 5) {
const logDir = path.dirname(logPath);
const logBase = path.basename(logPath, '.log');
// 压缩当前日志文件
if (fs.existsSync(logPath)) {
const date = new Date().toISOString().replace(/[:.]/g, '-');
const compressedPath = path.join(logDir, `${logBase}-${date}.log.gz`);
const input = fs.createReadStream(logPath);
const output = fs.createWriteStream(compressedPath);
const compress = zlib.createGzip();
input.pipe(compress).pipe(output).on('finish', () => {
fs.unlinkSync(logPath);
cleanupOldLogs(logDir, logBase, maxFiles);
});
}
}
function cleanupOldLogs(logDir, logBase, maxFiles) {
fs.readdir(logDir, (err, files) => {
if (err) return;
const logFiles = files
.filter(file => file.startsWith(logBase) && file.endsWith('.gz'))
.sort()
.reverse();
logFiles.slice(maxFiles).forEach(file => {
fs.unlinkSync(path.join(logDir, file));
});
});
}
// 每天午夜执行轮转
setInterval(() => {
const now = new Date();
if (now.getHours() === 0 && now.getMinutes() === 0) {
rotateLog('/var/log/myapp/application.log', 7);
}
}, 60000); // 每分钟检查一次
选择哪种方法取决于你的具体需求、部署环境和运维策略。生产环境通常推荐结合系统工具(如logrotate)和应用程序级日志管理。