Ubuntu 下用结构化日志分析 Node.js 用户行为
一 整体思路与关键指标
二 日志采集与结构化落地
// 安装:npm i winston morgan
const winston = require('winston');
const express = require('express');
const morgan = require('morgan');
const logger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' })
]
});
const app = express();
app.use(express.json());
// HTTP 访问日志(结构化)
app.use(morgan('combined', {
stream: { write: msg => logger.info({ event: 'http_request', msg }) }
}));
// 业务行为日志
app.post('/login', (req, res) => {
const { username } = req.body;
logger.info({
event: 'login',
userId: req.headers['x-user-id'] || 'anonymous',
username,
ip: req.ip,
ua: req.headers['user-agent'],
status: 'success'
});
res.json({ ok: true });
});
app.listen(3000, () => logger.info({ event: 'server_start', port: 3000 }));
三 快速分析命令与脚本
grep '"event":"page_view"' combined.log | awk '{page=$3; gsub(/"/,"",page); count[page]++}
END {for(p in count) print p, count[p]}' | sort -nr
grep '"event":"login".*"status":"success"' combined.log | wc -l
awk -F'"timestamp":"' '{ts=$2; gsub(/T.*Z/,"",ts); m[ts]++}
END {for(t in m) print t, m[t]}' combined.log | sort
awk -F'"status":' '{s=$2; gsub(/,.*/,"",s); if(s~/^5/) err++; total++; }
END {printf "Error rate: %.2f%%\n", err/total*100}' combined.log
# 假设日志按时间排序;按 userId + page 分组,计算相邻时间差(秒)
awk -F'"timestamp":"' -F'"userId":"' '
$2 ~ /T/ {t=$2; sub(/T.*Z/,"",t); gsub(/"/,"",$4); k=$4":"$6;
if(k in last) dur[k]+=t-last[k]; else dur[k]=0; last[k]=t}
END {for(k in dur) print k, dur[k]}' combined.log
// page-views.js
const fs = require('fs');
const readline = require('readline');
const counts = {};
const rl = readline.createInterface({ input: fs.createReadStream('combined.log'), crlfDelay: Infinity });
rl.on('line', line => {
try {
const e = JSON.parse(line);
if (e.event === 'page_view' && e.page) counts[e.page] = (counts[e.page] || 0) + 1;
} catch {}
});
rl.on('close', () => console.log(counts));
journalctl -u your-app.service -o json 导出结构化日志后再分析。四 集中化与可视化方案
五 运维与合规要点