在Node.js开发过程中,日志归档始终是一个不可忽视的关键环节——毕竟,谁也不希望日志文件无限增长,最终导致磁盘空间被占满。幸运的是,无论你是选择使用第三方库,还是利用Node.js内置模块,实现日志归档都并不复杂。下面直接为大家分享实用的解决方案。

方法一:借助winston库轻松实现日志归档
如果你不介意使用第三方库,winston无疑是Node.js社区中最成熟、最受欢迎的日志处理方案之一。它内置了日志分割、压缩归档、保留天数管理等功能,帮你省去手动实现这些逻辑的繁琐工作。
首先,通过npm安装:
npm install winston
接着,创建一个名为logger.js的文件,配置日志归档逻辑:
const winston = require('winston');
const { combine, timestamp, printf } = winston.format;
// 自定义日志格式
const myFormat = printf(({ level, message, timestamp }) => {
return `${timestamp} ${level.toUpperCase()}: ${message}`;
});
// 创建一个logger实例
const logger = winston.createLogger({
level: 'info',
format: combine(timestamp(), myFormat),
transports: [
new winston.transports.File({ filename: 'logs/error.log', level: 'error' }),
new winston.transports.File({ filename: 'logs/combined.log' }),
],
});
// 日志归档的核心:按天轮转
const archive = new winston.transports.DailyRotateFile({
filename: 'logs/logs-%DATE%.log',
datePattern: 'YYYY-MM-DD',
zippedArchive: true, // 压缩历史日志
maxSize: '20m', // 单个文件大小上限
maxFiles: '14d', // 保留14天内的日志
});
logger.add(archive);
module.exports = logger;
使用时,只需引入该模块即可:
const logger = require('./logger');
logger.info('Hello, world!');
完成上述配置后,日志会自动按天生成独立的文件,历史日志会被压缩归档,超过14天的日志会被自动清理——真正实现“开箱即用”的便捷体验。
方法二:使用Node.js内置fs模块手动实现日志归档
如果你希望避免引入第三方依赖,可以仅使用Node.js自带的fs模块,配合moment(当然,你也可以用原生Date对象替代它)来实现日志归档。以下是一个简洁但功能完整的示例:
const fs = require('fs');
const path = require('path');
const os = require('os');
const moment = require('moment'); // 如果不想引入moment,可以用Date自己处理格式化
const logDir = path.join(__dirname, 'logs');
const archiveDir = path.join(logDir, 'archive');
// 确保目录存在
if (!fs.existsSync(logDir)) {
fs.mkdirSync(logDir);
}
if (!fs.existsSync(archiveDir)) {
fs.mkdirSync(archiveDir);
}
const logFile = path.join(logDir, 'app.log');
const archiveLogFile = path.join(archiveDir, `app-${moment().format('YYYY-MM-DD')}.log`);
function logToFile(message) {
const timestamp = moment().format('YYYY-MM-DD HH:mm:ss');
const logEntry = `${timestamp}: ${message}\n`;
fs.appendFile(logFile, logEntry, (err) => {
if (err) console.error('Error writing to log file:', err);
});
// 每天归档:如果当前日期与前一天的日期不同,就把旧日志文件移到归档目录
if (moment().format('YYYY-MM-DD') !== moment().subtract(1, 'days').format('YYYY-MM-DD')) {
fs.rename(logFile, archiveLogFile, (err) => {
if (err) console.error('Error archiving log file:', err);
});
}
}
logToFile('Hello, world!');
这种手动方案的优势在于轻量、灵活可控,但缺点也很突出:开发者需要自行处理日期比较、文件重命名、并发写入等细节。如果项目规模较小,或者对第三方依赖有严格限制,这种“手写”方式完全可以胜任。不过,在生产环境中,仍然建议使用winston等成熟库,以避免潜在问题。
