Node.js 应用在 Ubuntu 上的性能日志分析实操指南
一 目标与总体流程
二 日志采集与结构化
npm i winston// logger.js
const winston = require('winston');
const { createLogger, format, transports } = winston;
const { combine, timestamp, json } = format;
const logger = createLogger({
level: 'info',
format: combine(timestamp(), json()),
transports: [
new transports.File({ filename: 'error.log', level: 'error' }),
new transports.File({ filename: 'combined.log' })
]
});
function withTiming(req, res, next) {
const start = process.hrtime.bigint();
const traceId = req.headers['x-trace-id'] || require('crypto').randomUUID();
req.traceId = traceId;
res.setHeader('x-trace-id', traceId);
res.on('finish', () => {
const end = process.hrtime.bigint();
const durationMs = Number(end - start) / 1e6;
logger.info('http_request', {
traceId, method: req.method, url: req.url,
statusCode: res.statusCode, durationMs, userAgent: req.headers['user-agent']
});
});
next();
}
module.exports = { logger, withTiming };
三 系统级与 APM 监控
pm2 start app.js --name api && pm2 monitnode --prof app.js,生成v8.log,再用node --prof-process分析热点函数。node --inspect app.js,通过Chrome DevTools进行采样与火焰图分析。四 日志分析与可视化
jq -r 'select(.msg=="http_request") | [.url, .durationMs] | @tsv' combined.log \
| sort -k2 -nr | head -10
# 错误率(按行计数)
wc -l combined.log | awk '{total=$1} END {print "total:", total}'
grep -c '"level":"error"' combined.log | awk '{err=$1; getline total < "total.tmp"; printf "error_rate: %.2f%%\n", err/total*100}'
# Top 5 URL 错误
jq -r 'select(.level=="error" and .msg=="http_request") | .url' combined.log \
| sort | uniq -c | sort -nr | head -5
awk '/"timestamp":"2025-04-01T[0-9]{2}:[0-9]{2}:[0-9]{2}/' combined.log > day.log
五 日志轮转与维护
sudo nano /etc/logrotate.d/nodejs/var/log/nodejs/*.log {
daily
rotate 7
missingok
notifempty
compress
delaycompress
sharedscripts
postrotate
systemctl reload my-node-app >/dev/null 2>&1 || true
endscript
}