Node.js 日志选型指南:Winston vs Log4js 全方位对比与实战
在 Node.js 应用中,日志系统是不可或缺的组成部分。winston 和 log4js 是目前社区最流行的两个日志库,它们各有千秋。本文将从基础使用(含日志级别、日志轮转)入手,给出可直接运行的代码示例,并总结关键注意事项,最后结合对比表格给出选型建议。
一、快速上手:基础配置与日志轮转
1. Winston 实战
安装
:::code-group
sh
npm install winston winston-daily-rotate-file
sh
pnpm add winston winston-daily-rotate-file
:::
基础配置(日志级别)
javascript
const winston = require('winston');
const logger = winston.createLogger({
// 日志级别:error, warn, info, http, verbose, debug, silly
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.printf(({ timestamp, level, message }) => {
return `${timestamp} [${level.toUpperCase()}]: ${message}`;
})
),
transports: [
new winston.transports.Console({
level: 'debug', // 控制台单独设置级别
format: winston.format.simple()
}),
new winston.transports.File({
filename: 'logs/app.log',
level: 'info'
})
]
});
// 使用示例
logger.error('数据库连接失败');
logger.warn('内存使用率超过80%');
logger.info('服务启动成功,监听端口3000');
logger.debug('请求参数:', { userId: 123 }); // 不会输出,因为文件级别为 info
日志轮转配置
借助 winston-daily-rotate-file 实现按天切割、自动清理。
javascript
const winston = require('winston');
const DailyRotateFile = require('winston-daily-rotate-file');
const transport = new DailyRotateFile({
filename: 'logs/application-%DATE%.log',
datePattern: 'YYYY-MM-DD',
zippedArchive: true,
maxSize: '20m', // 单个文件最大 20MB
maxFiles: '14d' // 保留 14 天
});
const logger = winston.createLogger({
level: 'info',
transports: [
transport,
new winston.transports.Console()
]
});
2. Log4js 实战
安装
:::code-group
sh
npm install log4js
sh
pnpm add log4js
:::
基础配置(日志级别)
javascript
const log4js = require('log4js');
log4js.configure({
appenders: {
// 控制台输出
console: { type: 'console' },
// 文件输出
file: {
type: 'file',
filename: 'logs/app.log'
}
},
categories: {
default: {
appenders: ['console', 'file'],
level: 'info' // 全局级别
}
}
});
const logger = log4js.getLogger();
// 使用示例
logger.trace('跟踪信息'); // 级别最低
logger.debug('调试信息');
logger.info('普通信息');
logger.warn('警告信息');
logger.error('错误信息');
logger.fatal('致命错误');
日志轮转配置(内置支持)
Log4js 原生提供 dateFile 和 file 的轮转能力,无需额外依赖。
javascript
const log4js = require('log4js');
log4js.configure({
appenders: {
// 按天轮转
dailyFile: {
type: 'dateFile',
filename: 'logs/app.log',
pattern: 'yyyy-MM-dd',
keepFileExt: true, // 保留 .log 后缀
daysToKeep: 14, // 保留 14 天
compress: true // 压缩旧文件
},
// 按大小轮转
sizeFile: {
type: 'file',
filename: 'logs/size.log',
maxLogSize: 20 * 1024 * 1024, // 20MB
backups: 5 // 保留 5 个备份
}
},
categories: {
default: { appenders: ['dailyFile', 'sizeFile'], level: 'info' }
}
});
const logger = log4js.getLogger();
logger.info('这条日志会同时写入两个轮转文件中');
二、重要注意事项
⚠️ Winston 注意事项
-
日志轮转需要额外插件
核心库不提供轮转功能,必须搭配
winston-daily-rotate-file或winston-logrotate。记得定期清理或配置maxFiles,否则磁盘可能被撑爆。 -
异步日志与异常处理
Winston 默认同步写入,高并发下可能阻塞事件循环。建议启用
handleExceptions捕获未处理异常,或结合process.on('uncaughtException')使用。 -
性能开销
配置多个 Transport 或复杂 format(如
json()、prettyPrint())会显著降低吞吐量。生产环境建议关闭colorize和prettyPrint。 -
多实例共享文件
如果使用
Filetransport,多个进程写入同一文件可能导致日志混乱或丢失。推荐使用winston-daily-rotate-file的多进程选项,或改用流式日志服务。
⚠️ Log4js 注意事项
-
配置文件变更需要重启
Log4js 在应用启动时读取配置,运行时修改配置文件不会自动生效。如需动态调整级别,可以通过
log4js.getLogger().level在代码中修改。 -
异步模式下可能丢失日志
默认使用同步写入。若启用
pm2: true或配置type: 'multiFile'等异步附加器,进程异常退出时可能丢失最后几条日志。建议监听shutdown事件并调用log4js.shutdown()。 -
日志级别继承
每个 category 会继承
default级别,但若显式指定level会覆盖。注意additivity: false可避免重复输出。 -
与 PM2 兼容性
在 PM2 集群模式下,需配置
pm2: true和pm2InstanceVar: 'INSTANCE_ID',否则多个进程会争夺同一个日志文件。
三、核心差异对比
| 特性维度 | Winston | Log4js |
|---|---|---|
| 设计哲学 | 高度灵活,类似日志平台 | 类 Log4j,配置清晰直接 |
| 日志轮转 | 需要额外模块(winston-daily-rotate-file) |
内置支持(dateFile、file 轮转) |
| 性能基准 | ~30k logs/s(2025 年测试数据) | ~15k logs/s(同等环境) |
| 结构化日志 | 原生支持 JSON,可轻松扩展 | 支持 JSON,但扩展性稍弱 |
| 生态与下载量 | 周下载 1200 万+,GitHub 20k+ stars | 周下载 360 万,GitHub 5k+ stars |
| 多进程支持 | 需谨慎配置,推荐使用外部日志收集器 | PM2 集群需特殊配置 |
| 学习曲线 | 中等(概念较多:Transport、Format、ExceptionHandlers) | 低(配置简单,API 直观) |
| 典型场景 | 复杂企业应用、多路输出、需要高度定制 | Java 迁移团队、简单轮转需求、中小型项目 |
四、选型建议
选择 Winston,如果:
- 项目需要将日志同时发送到文件、数据库、Elasticsearch、第三方日志服务(如 Loggly、Datadog)。
- 团队追求极致性能和生态丰富度,未来可能需要自定义 Transport。
- 开发者熟悉函数式组合(
winston.format.combine)并乐于接受更多配置选项。
选择 Log4js,如果:
- 团队有 Java/Log4j 背景,希望保持类似的配置风格。
- 需要开箱即用的日志轮转,不想引入额外依赖。
- 项目规模较小,日志量不大,追求快速上手和最低心智负担。
性能极致场景: 两者都可满足大部分应用。若每秒写入超过 5 万条日志,建议考虑基于流的方案(如 Pino 或 Bunyan)。
五、总结
Winston 和 Log4js 都是成熟可靠的日志库。Winston 胜在灵活与生态,Log4js 胜在简洁与集成轮转。实际开发中,可以先根据团队技术栈快速选择,再结合日志轮转、多进程等注意事项调整配置。无论选择哪个,都建议将日志写入本地文件后,由 Filebeat、Logstash 等工具统一采集,避免直接通过 HTTP 发送日志带来的性能损耗。