Ubuntu Node.js 日志与分布式系统调试技巧
一 日志体系搭建
- 使用结构化日志:在生产环境优先采用 JSON 格式,便于检索与聚合。Node.js 常用库包括 Winston、Pino、Bunyan;结合 Express 的 Morgan 记录 HTTP 访问日志。示例(Winston,开发/生产分流):
- 安装:
npm i winston morgan
- 配置:
- const winston = require(‘winston’); const morgan = require(‘morgan’);
- const logger = winston.createLogger({
level: process.env.NODE_ENV === ‘production’ ? ‘info’ : ‘debug’,
format: winston.format.json(),
transports: [
new winston.transports.File({ filename: ‘logs/error.log’, level: ‘error’ }),
new winston.transports.File({ filename: ‘logs/combined.log’ }),
…(process.env.NODE_ENV !== ‘production’ ? [new winston.transports.Console({ format: winston.format.simple() })] : [])
]
});
- app.use(morgan(‘combined’)); // 写入 stdout,由 PM2/系统收集
- 记录关键性能指标:在中间件或路由层埋点输出 响应时间、内存、CPU 等,用于定位瓶颈与异常波动。示例:
- const start = process.hrtime();
- // … 业务处理
- const [sec, nano] = process.hrtime(start); const latencyMs = (sec * 1e9 + nano) / 1e6;
- logger.info(‘Request completed’, { method: req.method, path: req.path, status: res.statusCode, latencyMs });
- setInterval(() => {
const mem = process.memoryUsage(); const cpu = process.cpuUsage();
logger.info(‘System metrics’, {
heapUsedMB: (mem.heapUsed / 1024 / 1024).toFixed(1),
cpuUserMs: (cpu.user / 1e6).toFixed(2)
});
}, 5000);
- 进程与日志聚合:使用 PM2 管理进程、统一收集日志、快速排查。
- 安装:
sudo npm i -g pm2
- 启动:
pm2 start app.js --name api --log /var/log/nodejs/api.log
- 实时查看:
pm2 logs api --lines 200
- 监控资源:
pm2 monit。
二 日志轮转与清理
- 系统级 logrotate(Ubuntu 自带):对日志按天轮转、压缩与保留,避免磁盘被占满。
- 新建配置:
sudo nano /etc/logrotate.d/nodejs
- 示例:
- /var/log/nodejs/*.log {
daily
rotate 7
compress
missingok
notifempty
create 0640 root adm
}
- 测试:
sudo logrotate -f /etc/logrotate.d/nodejs
- 应用级轮转:在代码中集成 winston-daily-rotate-file,按日期/大小切分并压缩归档。
- 安装:
npm i winston-daily-rotate-file
- 配置:
- const DailyRotateFile = require(‘winston-daily-rotate-file’);
- const transport = new DailyRotateFile({
filename: ‘logs/app-%DATE%.log’,
datePattern: ‘YYYY-MM-DD’,
zippedArchive: true,
maxSize: ‘20m’,
maxFiles: ‘14d’
});
- PM2 内置日志轮转:在 ecosystem.config.js 中配置按大小/时间切分与保留。
- 示例:
- module.exports = { apps: [{ name: ‘api’, script: ‘app.js’,
out_file: ‘/var/log/nodejs/api-out.log’,
error_file: ‘/var/log/nodejs/api-err.log’,
log_date_format: ‘YYYY-MM-DD HH:mm Z’,
max_size: ‘10M’, retain: 7, merge_logs: true }] };
- 命令:
pm2 start ecosystem.config.js。
三 本地与远程调试
- 内置调试与 Chrome DevTools:快速断点、观察调用栈与性能。
- 启动:
node --inspect-brk app.js
- 打开 chrome://inspect 进行断点调试与 CPU/内存分析。
- VS Code 调试:配置 launch.json 一键启动与断点调试。
- 示例:
- {
“version”: “0.2.0”,
“configurations”: [
{
“type”: “node”,
“request”: “launch”,
“name”: “Launch App”,
“program”: “${workspaceFolder}/app.js”,
“skipFiles”: [“<node_internals>/**”]
}
]
}
- 远程/容器场景:使用 Remote-SSH / Remote-Containers 连接远端或容器,在本地 VSCode 中直接调试运行中的服务;结合端口转发与任务系统,打通调试闭环。
四 分布式系统调试
- 集中式日志与可视化:搭建 ELK(Elasticsearch + Logstash + Kibana) 或 Graylog,统一采集、解析与可视化 JSON 日志,便于跨服务检索与聚合分析。
- 分布式追踪:在关键路径注入 trace_id / span_id,接入 Jaeger / Zipkin / OpenTelemetry,还原跨进程调用链,定位延迟与异常来源。
- 日志与追踪联动:在日志中输出 trace_id,并在 VSCode 中配置任务/快捷方式,自动跳转到 Jaeger/Zipkin UI 查询完整调用链,提升排查效率。
- 容器与编排环境:在 Kubernetes 中通过 DaemonSet 采集容器日志,或使用 Sidecar 模式将应用日志转发至后端;结合集群级日志/追踪平台实现统一观测。
五 高效排障命令与 APM
- 命令行快速分析(适用于 JSON 行日志,如 combined.log):
- 统计平均延迟(假设字段为 latencyMs):
awk -F'latencyMs":' '{if($2) {sum+=$2; count++}} END {print "Avg latency:", sum/count "ms"}' combined.log
- 错误类型分布:
grep 'ERROR' combined.log | awk -F'"message":' '{print $2}' | sort | uniq -c | sort -nr | head
- 按 trace_id 拉取完整调用链日志:
grep 'trace_id":"abc123"' combined.log | jq .(需安装 jq)
- 性能与错误归因:接入 APM(如 New Relic、Datadog、Elastic APM),获得 数据库/外部 API 耗时、错误追踪与调用拓扑,减少手工埋点与推断成本。