Ubuntu下Node.js日志配置方法
在Ubuntu环境下配置Node.js日志系统,涵盖基础console.log调试、Winston与Morgan第三方库、日志轮转防止磁盘溢出、PM2进程管理及环境变量动态控制日志级别,实现日志分级、自定义格式与自动轮转,满足开发调试与生产运维需求。
在 Ubuntu 环境下配置 Node.js 的日志系统,几乎是每个后端开发者都要面对的基础功课。不管你是刚入门的小白,还是已经在生产环境摸爬滚打多年的老手,日志这件事儿——说大不大,说小不小——但一旦出了问题,定位起来真要命。下面从最基础的console.log说起,一路聊到企业级的轮转与进程管理,希望能帮你搭一套既顺手又靠谱的日志体系。

1. 使用内置 console.log(基础调试)
console.log 是 Node.js 自带的最朴素的日志方式,开发阶段快速打点、查看变量值确实方便。不过如果想让输出更有可读性,可以手动拼接时间戳等上下文信息:
const express = require('express');
const app = express();
const port = 3000;
app.get('/', (req, res) => {
console.log(`[${new Date().toISOString()}] INFO: Request received at ${req.url}`);
res.send('Hello World!');
});
app.listen(port, () => {
console.log(`[${new Date().toISOString()}] INFO: Server running at http://localhost:${port}/`);
});
缺点很明显:没法灵活控制日志级别(比如区分 debug、warn、error),格式也不统一,更别提持久化到文件了。所以这玩意儿适合快速原型或本地调试,上生产环境基本不够用。
2. 使用第三方日志库(推荐生产环境)
2.1 Winston(通用灵活)
Winston 可以说是 Node.js 圈子里最流行的日志库了。它支持多种传输方式(控制台、文件、远程服务器等),还能自定义日志级别和格式,几乎能应付所有常见的日志需求。
- 安装:
npm install winston - 配置示例(创建
logger.js):const { createLogger, format, transports } = require('winston'); const logger = createLogger({ level: process.env.LOG_LEVEL || 'info', // 通过环境变量设置日志级别 format: format.combine( format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), format.printf(({ timestamp, level, message }) => `[${timestamp}] ${level}: ${message}`) ), transports: [ new transports.Console(), new transports.File({ filename: 'logs/error.log', level: 'error' }), new transports.File({ filename: 'logs/combined.log' }) ] }); if (process.env.NODE_ENV !== 'production') { logger.add(new transports.Console({ format: format.simple() })); } module.exports = logger; - 使用示例:
const logger = require('./logger'); logger.info('Application started'); logger.error('Something went wrong!');
优点很突出:功能全面、分级清晰、输出灵活,很适合中大型项目。不过配置起来稍微有点琐碎,但只要搭好一次后面就一劳永逸。
2.2 Morgan(HTTP 请求日志中间件)
Morgan 是专门为 HTTP 请求日志而生的中间件,和 Express 或 Koa 搭配起来非常顺手。它能自动记录请求方法、路径、状态码、耗时等信息,格式规范,便于分析流量和性能瓶颈。
- 安装:
npm install morgan - 配置示例:
const express = require('express'); const morgan = require('morgan'); const fs = require('fs'); const path = require('path'); const app = express(); const port = 3000; const accessLogStream = fs.createWriteStream(path.join(__dirname, 'logs/access.log'), { flags: 'a' }); app.use(morgan('combined', { stream: accessLogStream })); app.get('/', (req, res) => { res.send('Hello World!'); }); app.listen(port, () => { console.log(`Server running at http://localhost:${port}/`); });
如果你已经有了 Winston 这样的通用日志库,通常不需要再单独用 Morgan 写文件——可以直接把 Morgan 的输出流指向 Winston 的传输,但这里把它单独拎出来讲,是因为它的 combined 格式 是 Apache 标准格式,很多日志分析工具(比如 GoAccess、ELK)可以直接解析,省去自己写解析器的麻烦。
3. 日志轮转(防止日志撑爆磁盘)
生产环境运行一段时间后,日志文件很容易变成几个 GB 的庞然大物,不仅占用磁盘,还拖慢后续的查询和归档速度。这时候就需要日志轮转——按天或按大小分割日志,自动压缩旧的,保留固定天数或份数。
推荐使用 winston-daily-rotate-file 这个库,和 Winston 无缝集成:
- 安装:
npm install winston-daily-rotate-file - 配置示例(修改
logger.js):const { createLogger, format, transports } = require('winston'); const DailyRotateFile = require('winston-daily-rotate-file'); const logger = createLogger({ level: 'info', format: format.combine( format.timestamp(), format.json() ), transports: [ new DailyRotateFile({ filename: 'logs/application-%DATE%.log', datePattern: 'YYYY-MM-DD', zippedArchive: true, maxSize: '20m', maxFiles: '14d' }), new transports.Console() ] }); module.exports = logger;
上面这配置的意思是:每天生成一个带日期的日志文件,旧日志自动压缩成 .gz,单个文件超过 20MB 也会触发新文件,保留最近 14 天的日志。对于大多数业务场景,这个策略基本够用。
4. 使用 PM2 管理日志(进程与日志分离)
PM2 是 Node.js 最流行的进程管理工具,自带日志管理功能。用 PM2 启动应用后,它会把 stdout 和 stderr 分别输出到文件,支持日志轮转、尾随查看等操作。适合不想在代码层面折腾繁琐日志配置的场景。
- 安装 PM2:
npm install pm2 -g - 启动应用并管理日志:
pm2 start app.js --name my-app pm2 logs my-app # 查看实时日志 pm2 logs my-app --lines 100 # 查看最近100行 # 配置日志轮转(全局) pm2 set pm2-logrotate:max_size 10M # 单个文件最大10MB pm2 set pm2-logrotate:retain 7 # 保留7天日志
PM2 的日志方案优点在于“无侵入”——你甚至不需要在代码里引入任何日志库,直接用 console.log 就能被 PM2 捕获并写入文件。当然,如果项目已经用了 Winston,也可以两边共存,互不冲突。
5. 通过环境变量配置日志级别
不同环境下对日志的粒度要求不一样:开发阶段希望看到 debug 信息,生产环境只关心 warn 和 error。通过环境变量动态调整日志级别,是成本最低也最灵活的做法。
- 设置环境变量启动:
# 开发环境 LOG_LEVEL=debug node app.js # 生产环境 LOG_LEVEL=info node app.js - 代码中使用(Winston 示例):
const logger = createLogger({ level: process.env.LOG_LEVEL || 'info', // ... 其他配置 });
这样一来,同一个代码包部署到不同环境,只需调整环境变量即可控制日志输出量,完全不需要改动代码。这种做法也符合“配置即代码”的运维思路,值得养成习惯。


































