Ubuntu下JavaScript(Node.js)日志管理最佳实践
根据应用需求选型:
const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' }),
new winston.transports.Console() // 开发环境可输出到控制台
]
});
示例(Pino):
const pino = require('pino');
const logger = pino({ level: 'info' }, pino.destination('app.log'));
logger.info('Application started');
根据环境调整日志详细程度,避免不必要的性能消耗:
debug级别,输出详细调试信息;info或warn级别,仅记录关键操作(如请求响应、状态变更)和潜在问题(如数据库连接超时);error级别记录致命错误(如服务崩溃、未捕获异常)。const env = process.env.NODE_ENV || 'development';
const level = env === 'production' ? 'info' : 'debug';
const logger = winston.createLogger({ level });
避免单个日志文件过大导致磁盘空间耗尽,推荐两种方式:
winston-daily-rotate-file自动按日期分割日志,保留最近7天:const winston = require('winston');
require('winston-daily-rotate-file');
const transport = new winston.transports.DailyRotateFile({
filename: 'application-%DATE%.log',
datePattern: 'YYYY-MM-DD',
maxSize: '20m', // 单个文件最大20MB
maxFiles: '7d' // 保留7天
});
logger.add(transport);
logrotate配置文件示例(/etc/logrotate.d/nodejs-app):/var/log/nodejs/app.log {
daily
missingok
rotate 7
compress
delaycompress
notifempty
create 640 nodejs nodejs
}
避免同步写入阻塞主线程,提升应用性能。多数现代日志库(如Winston、Pino)默认支持异步:
transports的async选项开启(默认开启);const logger = winston.createLogger({
transports: [
new winston.transports.File({ filename: 'async.log', async: true })
]
});
以JSON格式输出日志,便于后续解析、过滤和分析(如通过ELK提取字段):
logger.info('User login', { userId: 123, ip: '192.168.1.1', status: 'success' });
// 输出:{"level":"info","message":"User login","userId":123,"ip":"192.168.1.1","status":"success"}
结构化日志的优势:
grep "userId":123 app.log);将日志发送至集中式系统,解决分布式应用日志分散问题,便于统一监控和分析:
winston-logstash插件);pm2 start app.js --log-date-format "YYYY-MM-DD HH:mm Z" # 格式化时间
pm2 logs myapi --lines 100 # 查看最近100行日志
console.log的性能);fs.writeFileSync等同步方法;transports支持buffer选项,批量写入磁盘减少I/O次数。640(所有者可读写,组可读),避免未授权访问:chown nodejs:nodejs /var/log/nodejs/app.log
chmod 640 /var/log/nodejs/app.log
winston-deny或自定义format移除日志中的敏感字段:const winston = require('winston');
const deny = require('winston-deny');
const logger = winston.createLogger({
format: winston.format.combine(
winston.format.json(),
deny({ paths: ['password', 'creditCard'] }) // 过滤指定字段
),
transports: [new winston.transports.File({ filename: 'secure.log' })]
});