在 Ubuntu 中设置 Node.js 日志的完整实践
一 基础方案选择
二 应用内日志配置示例
使用 winston 输出到控制台与文件(按级别分流)
npm install winstonconst winston = require('winston');
const logger = winston.createLogger({
level: process.env.LOG_LEVEL || 'info',
format: winston.format.combine(
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
winston.format.json()
),
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' }),
],
});
if (process.env.NODE_ENV !== 'production') {
logger.add(new winston.transports.Console({
format: winston.format.simple()
}));
}
logger.info('Hello World');
logger.error('Something went wrong');
LOG_LEVEL=debug node app.js。使用 morgan 记录 Express HTTP 请求日志到文件
npm install morganconst express = require('express');
const morgan = require('morgan');
const fs = require('fs');
const path = require('path');
const accessLogStream = fs.createWriteStream(
path.join(__dirname, 'access.log'), { flags: 'a' }
);
const app = express();
app.use(morgan('combined', { stream: accessLogStream }));
app.get('/', (req, res) => res.send('Hello World'));
app.listen(3000, () => console.log('Server on 3000'));
使用 log4js 按类别与日期切分输出
npm install log4jsconst log4js = require('log4js');
const path = require('path');
log4js.configure({
appenders: {
console: { type: 'console' },
file: {
type: 'file',
filename: path.join(__dirname, 'logs', 'app.log'),
maxLogSize: 10 * 1024 * 1024, // 10MB
backups: 5,
encoding: 'utf-8'
},
dateFile: {
type: 'dateFile',
filename: path.join(__dirname, 'logs', 'app'),
pattern: '.yyyy-MM-dd.log',
alwaysIncludePattern: true,
compress: true
}
},
categories: {
default: { appenders: ['console', 'file', 'dateFile'], level: 'debug' }
}
});
const logger = log4js.getLogger();
logger.info('Hello log4js');
logger.error('Oops');
三 运行方式与系统日志集成
npm install -g pm2pm2 start app.js --name my-apppm2 logs my-app(实时查看),pm2 logs my-app --err(仅错误),pm2 logs my-app --out(仅标准输出)module.exports = {
apps: [{
name: 'my-app',
script: 'app.js',
out_file: 'logs/out.log',
error_file: 'logs/err.log',
combine_logs: false
}]
};
[Unit]
Description=My Node.js App
After=network.target
[Service]
Type=simple
User=www-data
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/node /opt/myapp/app.js
Restart=always
StandardOutput=journal
StandardError=journal
SyslogIdentifier=myapp
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload && sudo systemctl enable --now myappjournalctl -u myapp -f(实时查看)journalctl -u myapp --since "2025-12-11 00:00:00"StandardOutput/StandardError 设为 syslog 并配合 SyslogIdentifier 使用。四 日志轮转与保留策略
/opt/myapp/logs/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
create 640 www-data www-data
copytruncate
}
daily 每日轮转;rotate 14 保留 14 份;compress 压缩归档;copytruncate 避免应用持有文件句柄(适合不支持信号重新打开日志的程序)。sudo logrotate -d /etc/logrotate.d/myapp(语法检查),sudo logrotate -f /etc/logrotate.d/myapp(强制执行一次)。npm install winston-daily-rotate-fileconst DailyRotateFile = require('winston-daily-rotate-file');
const transport = new DailyRotateFile({
filename: 'logs/application-%DATE%.log',
datePattern: 'YYYY-MM-DD',
zippedArchive: true,
maxSize: '20m',
maxFiles: '14d'
});
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [transport, new winston.transports.Console({ format: winston.format.simple() })]
});
五 生产环境建议