Node.js 应用跑在 Ubuntu 上后,日志很快就会从“排错工具”变成“磁盘负担”:文件越积越多、定位问题越来越慢,多机部署后还会出现分散难查的问题。要把这件事做好,关键不是盲目上平台,而是先分清你到底需要本机轮转、进程级管理,还是集中收集与可视化分析。
下面按常见部署方式梳理 5 种成熟做法:先看 Ubuntu 自带的 logrotate,再看 PM2 的内置日志能力、rsyslog/syslog-ng 的集中收集、ELK 这类分析平台,以及补充性的定时清理方案。读完后,你可以根据单机、多机、是否需要检索分析这几个维度,判断哪套组合更适合自己的环境。
为什么要给 Node.js 日志做自动化处理
在 Ubuntu 环境下,Node.js 日志自动化处理的核心思路并不复杂,通常就是几件事:轮转、压缩、清理,以及在需要时做集中管理。区别在于,不同方案的接入位置不同,有的依赖系统能力,有的依赖进程管理器,有的则面向多服务器和长期分析场景。
如果你的应用只是单机部署,优先考虑系统原生能力往往就够用;如果已经使用 PM2 管理进程,可以直接复用它的日志功能;而一旦进入多机部署、跨节点检索、可视化分析阶段,就需要把日志收集与处理链路往上提一层。
方案一:用 logrotate 做系统级轮转
logrotate 是 Ubuntu 自带的日志管理工具,也是最稳妥、最通用的基础方案。它能自动完成日志轮转、压缩和清理,适合绝大多数把日志写到文件的 Node.js 应用。

如果系统中未安装,可以执行:
sudo apt-get install logrotate
不过在 Ubuntu 中,它通常已经预装。接下来,在 /etc/logrotate.d/ 目录下新建一个 nodejs 文件,例如:
sudo nano /etc/logrotate.d/nodejs
写入如下配置,日志路径按实际情况调整:
/path/to/your/nodejs/logs/*.log {
daily # 每天轮转一次(可选:weekly/monthly)
rotate 7 # 保留最近7个轮转日志(避免无限堆积)
compress # 使用gzip压缩旧日志(节省空间)
delaycompress # 延迟压缩(如第8个日志才压缩第1个,减少IO压力)
missingok # 若日志文件不存在,不报错继续执行
notifempty # 若日志为空,不进行轮转
create 0640 root adm # 轮转后创建新日志文件,权限0640,属主root、属组adm
}
这份配置里最值得关注的参数
daily、rotate 7 和 compress 组成了最常见的保留策略:每天切分一次,保留 7 份历史文件,并对旧日志进行压缩。对于写入量中等的服务,这样的配置通常已经足够。
delaycompress 的作用是延后压缩,避免刚轮转的日志立刻被压缩,减少 I/O 压力;missingok 和 notifempty 则用来处理“日志不存在”或“日志为空”的常见情况,避免任务报错或做无意义轮转。create 0640 root adm 会在轮转后创建新日志文件,并指定权限与属主属组,这一点对生产环境尤其重要。
如何验证配置已经生效
配置完成后,可以手动触发一次轮转:
sudo logrotate -f /etc/logrotate.d/nodejs
这样可以直接检查路径、权限和轮转逻辑是否正确。正常情况下,logrotate 会通过 /etc/cron.daily/logrotate 每日自动执行,因此大多数环境不需要再额外加调度任务。
方案二:使用 PM2 内置日志管理
如果你的 Node.js 应用本来就是用 PM2 部署的,那就可以直接利用 PM2 的日志能力,不必再额外拼装一套文件管理逻辑。这个方案的优点是离应用更近,部署时也更顺手。
先安装 PM2:
sudo npm install pm2 -g
启动应用时指定标准输出和错误日志路径:
pm2 start app.js --name "my-app"
--out-file /var/log/nodejs/my-app-out.log # 标准输出日志路径
--error-file /var/log/nodejs/my-app-err.log # 错误输出日志路径
用 ecosystem.config.js 管理日志参数
PM2 的轮转参数可以通过 pm2 set pm2:logrotate 命令设置,也可以直接写进 ecosystem.config.js。后者更适合版本化管理和多人协作。
module.exports = {
apps: [{
name: 'my-app',
script: 'app.js',
out_file: '/var/log/nodejs/my-app-out.log',
error_file: '/var/log/nodejs/my-app-err.log',
log_date_format: 'YYYY-MM-DD HH:mm Z', // 日志时间格式
time: true, // 在日志中添加时间戳
merge_logs: true, // 合并stdout/stderr
max_size: '10M', // 单个日志文件最大10MB
max_files: 7 // 保留7个历史日志文件
}]
};
加载配置启动应用:
pm2 start ecosystem.config.js
PM2 方案适合什么场景
如果你已经用 PM2 管理进程,直接在 PM2 层控制日志输出、时间戳和大小限制,维护成本会更低。像 max_size: '10M' 和 max_files: 7 这种参数,能比较直观地控制日志增长速度。
不过它更适合单机或少量节点环境。到了多机统一检索、审计留存或复杂查询分析阶段,PM2 本身并不能替代集中式日志系统。
方案三:结合 rsyslog/syslog-ng 做集中收集
当 Node.js 应用部署到多台服务器后,日志分散在各节点上,单靠本地文件轮转已经不够。这个时候,可以用 rsyslog 或 syslog-ng 把日志集中收集到固定位置,再统一处理。
安装 rsyslog:
sudo apt-get install rsyslog
Ubuntu 通常默认已经安装。接着新建配置文件 /etc/rsyslog.d/50-nodejs.conf,写入:
if $programname == 'node' then /var/log/nodejs/nodejs.log
& stop # 停止后续规则处理,避免重复记录
重启服务让配置生效:
sudo systemctl restart rsyslog
这套链路解决了什么问题
配置生效后,Node.js 的标准输出和错误输出会被 rsyslog 捕获,并写入 /var/log/nodejs/nodejs.log。这样做的意义在于先把输出入口统一,再结合 logrotate 对目标文件做后续轮转和压缩。
其中 & stop 很关键,它会停止后续规则处理,避免同一条日志被重复记录。这种方式特别适合多台 Ubuntu 服务器统一接入系统日志体系的场景。
方案四:接入 ELK 等平台做分析与可视化
如果你不仅要“存得下”,还要“查得快、看得懂”,那么就需要更完整的日志平台。常见选择包括 ELK Stack(Elasticsearch + Logstash + Kibana)和 Graylog。前者在技术团队中更常见,适合做长期留存、检索、过滤和可视化。

安装组件:
sudo apt-get install elasticsearch logstash kibana
这里需要根据组件要求调整 Java 版本。然后创建 /etc/logstash/conf.d/nodejs.conf,让 Logstash 收集 Node.js 日志:
input {
file {
path => "/var/log/nodejs/*.log" # 日志文件路径
start_position => "beginning" # 从文件开头读取(首次配置时需开启)
sincedb_path => "/dev/null" # 忽略sincedb文件(测试用)
}
}
filter {
# 可选:添加过滤器解析日志(如grok解析JSON格式)
grok {
match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:loglevel} %{GREEDYDATA:logmessage}" }
}
date {
match => [ "timestamp", "ISO8601" ]
} # 转换时间格式
}
output {
elasticsearch { hosts => ["localhost:9200"] } # 发送到Elasticsearch
stdout { codec => rubydebug } # 控制台输出(测试用)
}
启动服务:
sudo systemctl start elasticsearch logstash kibana
之后通过 http://localhost:5601 访问 Kibana,创建索引模式,例如 nodejs-*,就可以开始做可视化和查询。
什么时候值得上 ELK
ELK 更适合这几类需求:日志量较大、需要结构化检索、要跨时间范围分析、要做仪表盘展示,或者要长期保存历史日志。相比单纯的文件轮转,它的成本更高,部署和资源占用也更重,但换来的能力是检索和分析效率的大幅提升。
如果你当前只是想解决磁盘占用和历史保留问题,先上 logrotate 或 PM2 往往更划算;只有在“日志已经成为运营和排障数据源”时,ELK 才真正体现价值。
方案五:补充旧日志自动清理
除了依赖 logrotate 的 rotate 参数,你还可以通过 cron 或 Node.js 脚本,定期删除过期日志。这个方案适合作为补充措施,用来清理特定目录中的老文件,尤其是在日志来源复杂、文件命名不完全统一时。
直接用 cron 删除过期日志
编辑当前用户的 crontab:
crontab -e
添加以下任务,每天凌晨 1 点删除 7 天前的 .log 文件:
0 1 * * * find /path/to/your/nodejs/logs -type f -name "*.log" -mtime +7 -exec rm -f {} ;
这类方式足够直接,但也更依赖路径和匹配规则是否写对,生产环境使用前最好先确认目录范围,避免误删。
用 Node.js 脚本做更细粒度清理
如果你想根据修改时间、文件类型或业务规则做更细的控制,也可以写一个 Node.js 脚本。比如创建 clean_logs.js:
const fs = require('fs');
const path = require('path');
const logDir = '/path/to/your/nodejs/logs';
const maxAge = 7 * 24 * 60 * 60 * 1000; // 7天的毫秒数
fs.readdir(logDir, (err, files) => {
if (err) throw err;
files.forEach(file => {
const filePath = path.join(logDir, file);
fs.stat(filePath, (err, stats) => {
if (err) throw err;
if (stats.isFile() && Date.now() - stats.mtime > maxAge) {
fs.unlink(filePath, err => {
if (err) throw err;
console.log(`Deleted: ${filePath}`);
});
}
});
});
});
再通过 cron 定时执行:
0 2 * * * /usr/bin/node /path/to/clean_logs.js
这种做法的优点是灵活,缺点是你需要自己承担脚本维护和异常处理工作,所以更适合作为补充,而不是替代成熟的轮转机制。
如何选型:单机先简化,多机再升级
如果是普通单机 Node.js 服务,优先级通常是 logrotate,因为它稳定、简单、系统原生;如果应用已经交给 PM2 管理,那么直接使用 PM2 的日志配置会更顺手。
如果进入多服务器部署,希望把不同节点的日志汇总到统一位置,可以加入 rsyslog/syslog-ng;如果还需要检索、过滤、统计和图形化展示,再考虑 ELK 或 Graylog 这类平台。至于 cron 和 Node.js 清理脚本,更适合作为补位手段,用来处理超期文件或特殊目录。
简单说,日志自动化处理并没有唯一标准答案,但有一条实用路线:先解决“不会堆满磁盘”,再解决“能统一收集”,最后才是“能分析和可视化”。按这个顺序落地,通常最省成本,也最不容易过度设计。







