2026-05-10 13:12:44 +08:00

119 lines
3.1 KiB
JavaScript

// exe-engine/src/monitor/dashboard.js
// EXE-Engine · 监控仪表盘
// 实时指标采集与快照
// PRJ-EXE-001 · Phase 1 · ZY-EXE-P1-006
// 版权:国作登字-2026-A-00037559
'use strict';
/**
* 监控仪表盘
*
* 本体论锚定:仪表盘 = 笔的健康面板。
* 每秒写了多少字、响应多快、用了多少墨水、出了几次错,
* 一切尽在仪表盘。
*/
class MonitorDashboard {
/**
* @param {object} deps
* @param {ResourceMeter} deps.resourceMeter 资源计量器
*/
constructor(deps = {}) {
this._resourceMeter = deps.resourceMeter || null;
this._metrics = [];
}
/**
* 记录一个指标数据点
* @param {string} name 指标名称
* @param {number} value 指标值
* @param {object} [tags] 标签
*/
recordMetric(name, value, tags = {}) {
this._metrics.push({
name,
value,
tags,
timestamp: Date.now()
});
}
/**
* 获取指定时间范围内的指标
* @param {string} name 指标名称
* @param {number} [timeRangeMs=60000] 时间范围(毫秒)
* @returns {object[]}
*/
getMetrics(name, timeRangeMs = 60000) {
const cutoff = Date.now() - timeRangeMs;
return this._metrics.filter(m =>
m.name === name && m.timestamp >= cutoff
);
}
/**
* 获取系统快照
* @returns {object}
*/
getSnapshot() {
const now = Date.now();
const oneMinuteAgo = now - 60000;
// 最近一分钟的请求计数
const recentRequests = this._metrics.filter(m =>
m.name === 'request_count' && m.timestamp >= oneMinuteAgo
);
// 最近一分钟的延迟
const recentLatency = this._metrics.filter(m =>
m.name === 'latency_ms' && m.timestamp >= oneMinuteAgo
);
// 最近一分钟的 token 消耗
const recentTokens = this._metrics.filter(m =>
m.name === 'tokens_used' && m.timestamp >= oneMinuteAgo
);
// 最近一分钟的错误
const recentErrors = this._metrics.filter(m =>
m.name === 'error_count' && m.timestamp >= oneMinuteAgo
);
// 计算 QPS
const qps = recentRequests.length > 0
? recentRequests.reduce((sum, m) => sum + m.value, 0) / 60
: 0;
// 计算平均延迟
const avgLatency = recentLatency.length > 0
? recentLatency.reduce((sum, m) => sum + m.value, 0) / recentLatency.length
: 0;
// 总 token 数
const totalTokens = recentTokens.reduce((sum, m) => sum + m.value, 0);
// 错误率
const totalRequests = recentRequests.reduce((sum, m) => sum + m.value, 0);
const totalErrors = recentErrors.reduce((sum, m) => sum + m.value, 0);
const errorRate = totalRequests > 0 ? totalErrors / totalRequests : 0;
return {
qps: Math.round(qps * 1000) / 1000,
avgLatency: Math.round(avgLatency * 100) / 100,
totalTokens,
errorRate: Math.round(errorRate * 10000) / 10000,
metricsCount: this._metrics.length,
timestamp: new Date().toISOString()
};
}
/**
* 清除所有已采集的指标
*/
resetMetrics() {
this._metrics = [];
}
}
module.exports = MonitorDashboard;