Node.js日志自动化分析实战方案
一 架构与流程
二 落地方案对比
| 方案 | 组件与栈 | 适用场景 | 优点 | 注意事项 |
|---|---|---|---|---|
| 自建 ELK | Elasticsearch + Logstash/Filebeat + Kibana | 需要复杂查询、可视化与全文检索 | 生态成熟、可视化强 | 资源开销较大,需调优 |
| 轻量集中式 | Grafana Loki + Promtail + Grafana | 成本敏感、云原生/微服务 | 低成本、与 Grafana 深度集成 | 全文检索能力弱于 ES |
| 自建脚本 + ES | Node.js + node-cron + @elastic/elasticsearch | 已有 ES、需定制报表/聚合 | 灵活可控、易集成业务指标 | 需自行处理容错与幂等 |
| 离线脚本 | bash/python + grep/awk + cron | 小规模或临时分析 | 简单快速、零依赖 | 难以支撑实时与交互分析 |
三 关键配置与示例代码
// logger.js
const winston = require('winston');
const { combine, timestamp, json, errors } = winston.format;
const logger = winston.createLogger({
level: 'info',
format: combine(timestamp(), errors({ stack: true }), json()),
defaultMeta: { service: 'order-service' },
transports: [
new winston.transports.Console(),
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' })
]
});
module.exports = logger;
/var/log/nodejs/*.log {
daily
missingok
rotate 7
compress
notifempty
create 640 root adm
}
// jobs/errorAnalysis.js
import { CronJob } from 'node-cron';
import { Client } from '@elastic/elasticsearch';
const client = new Client({ node: 'http://localhost:9200' });
export const errorAnalysisJob = new CronJob(
'0 0 */2 * * *', // 每2小时
async () => {
try {
const res = await client.search({
index: 'nodejs-logs-*',
body: {
size: 0,
query: {
bool: {
must: [
{ range: { '@timestamp': { gte: 'now-2h' } } },
{ term: { level: 'ERROR' } }
]
}
},
aggs: {
by_service: {
terms: { field: 'service.keyword' },
aggs: { by_msg: { terms: { field: 'error.message.keyword', size: 10 } } }
}
}
}
});
console.log('Error summary:', JSON.stringify(res.aggregations.by_service.buckets, null, 2));
// TODO: 发送告警/写入报表
} catch (err) {
console.error('Analysis job failed:', err);
}
},
null, true, 'Asia/Shanghai'
);
sum(rate({job="nodejs"} |= "ERROR" [5m])) / sum(rate({job="nodejs"}[5m]))topk(10, {job="nodejs"} |= "ERROR" | regexp "error_id=(?P<id>\\w+)" | line_format "{{.id}}")四 自动化分析任务清单
五 最佳实践与排错建议