v0.32.2
This commit is contained in:
1 parent
bb025dcf44
commit
b0f211555a
74 files changed
+6089
-556
No files matched your search
@@ -0,0 +1,128 @@
|
||||
window.rustProxyExtraOverview = (() => {
|
||||
const limit = 30;
|
||||
const names = [
|
||||
"extra_process_cpu", "extra_process_rss", "extra_process_fds", "extra_open_connections",
|
||||
"extra_websocket_active", "extra_tls_error_rate", "extra_request_error_rate",
|
||||
"extra_cache_hit_rate", "extra_cache_memory", "extra_h2_share",
|
||||
"extra_response_latency", "extra_backend_unhealthy",
|
||||
"extra_total_rps", "extra_active_exchanges", "extra_h1_share", "extra_h3_share",
|
||||
"extra_cache_miss_rate", "extra_backend_active",
|
||||
];
|
||||
const histories = new Map();
|
||||
const lastCounter = new Map();
|
||||
const lastValue = new Map();
|
||||
const lastUnits = new Map();
|
||||
const positive = value => value != null && Number.isFinite(Number(value)) && Number(value) >= 0 ? Number(value) : null;
|
||||
const node = id => document.querySelector(`[data-dashboard-widget="${id}"]`);
|
||||
function elapsedDelta(id, counters, now) {
|
||||
const old = lastCounter.get(id);
|
||||
const next = { values: counters, at: now };
|
||||
lastCounter.set(id, next);
|
||||
if (!old || now <= old.at || counters.some((v, i) => v < old.values[i])) return null;
|
||||
return { deltas: counters.map((v, i) => v - old.values[i]), seconds: (now - old.at) / 1000 };
|
||||
}
|
||||
function read(id, status, now, record) {
|
||||
const m = status.metrics || {}, d = status.system || {}, c = status.cache || {};
|
||||
const direct = {
|
||||
extra_process_cpu: d.process_cpu_percent,
|
||||
extra_process_rss: d.process_rss_bytes,
|
||||
extra_process_fds: d.open_fds,
|
||||
extra_open_connections: m.active_connections,
|
||||
extra_websocket_active: m.websocket_active,
|
||||
extra_response_latency: m.mean_duration_ms,
|
||||
extra_active_exchanges: m.active,
|
||||
};
|
||||
if (Object.hasOwn(direct, id)) {
|
||||
const numeric = positive(direct[id]);
|
||||
return {
|
||||
value: numeric, unit: id === "extra_process_cpu" ? "percent" : id === "extra_process_rss" ? "bytes" : id === "extra_response_latency" ? "ms" : "count",
|
||||
detail: id === "extra_process_fds" && positive(d.max_fds) ? `${t("overviewExtraFdLimit")}: ${fmt(d.max_fds)}` : ""
|
||||
};
|
||||
}
|
||||
if (id === "extra_backend_active") {
|
||||
const members = Array.isArray(status.backend_pools) ? status.backend_pools.flatMap(pool => pool.members || []) : null;
|
||||
return {
|
||||
value: members ? members.reduce((sum, member) => sum + (positive(member.active) ?? 0), 0) : null,
|
||||
unit: "count", detail: ""
|
||||
};
|
||||
}
|
||||
if (id === "extra_backend_unhealthy") {
|
||||
return {
|
||||
value: Array.isArray(status.backend_pools) ? status.backend_pools.reduce((sum, pool) =>
|
||||
sum + (pool.members || []).filter(member => member.status === "down").length, 0) : null, unit: "count", detail: ""
|
||||
};
|
||||
}
|
||||
if (id === "extra_cache_memory") {
|
||||
const bytes = positive(c.resident_bytes), budget = positive(c.hot_limit_bytes);
|
||||
const percent = budget && bytes !== null ? bytes / budget * 100 : null;
|
||||
return {
|
||||
value: percent === null ? bytes : percent, unit: percent === null ? "bytes" : "percent",
|
||||
detail: bytes === null ? "" : `${fmtBytes(bytes)}${budget ? ` / ${fmtBytes(budget)}` : ""}`
|
||||
};
|
||||
}
|
||||
if (!["extra_tls_error_rate", "extra_request_error_rate", "extra_cache_hit_rate", "extra_h2_share",
|
||||
"extra_total_rps", "extra_h1_share", "extra_h3_share", "extra_cache_miss_rate"].includes(id))
|
||||
return { value: null, unit: "count", detail: "" };
|
||||
const fields = ({
|
||||
extra_tls_error_rate: [m.tls_handshake_errors],
|
||||
extra_request_error_rate: [m.errors],
|
||||
extra_cache_hit_rate: [c.hits, c.misses],
|
||||
extra_h2_share: [m.http2_requests, m.requests],
|
||||
extra_h1_share: [m.http1_requests, m.requests],
|
||||
extra_h3_share: [m.http3_requests, m.requests],
|
||||
extra_total_rps: [m.requests],
|
||||
extra_cache_miss_rate: [c.misses],
|
||||
})[id].map(positive);
|
||||
const unit = ["extra_cache_hit_rate", "extra_h2_share", "extra_h1_share", "extra_h3_share"].includes(id)
|
||||
? "percent" : "rate";
|
||||
if (fields.some(v => v === null)) { lastCounter.delete(id); return { value: null, unit, detail: "" }; }
|
||||
if (!record) return { value: lastValue.get(id) ?? null, unit, detail: "" };
|
||||
const result = elapsedDelta(id, fields, now);
|
||||
if (!result) return { value: null, unit, detail: "" };
|
||||
const { deltas, seconds } = result;
|
||||
if (unit === "rate") return { value: deltas[0] / seconds, unit, detail: "" };
|
||||
const sum = id === "extra_cache_hit_rate" ? deltas[0] + deltas[1] : deltas[1];
|
||||
return { value: sum ? Math.min(100, deltas[0] / sum * 100) : null, unit, detail: "" };
|
||||
}
|
||||
function format(value, unit) {
|
||||
if (value == null) return "-";
|
||||
if (unit === "percent") return `${fmt(value, 1)}%`;
|
||||
if (unit === "bytes") return fmtBytes(value);
|
||||
if (unit === "ms") return `${fmt(value, 1)} ms`;
|
||||
if (unit === "rate") return `${fmt(value, 1)}/s`;
|
||||
return fmt(value);
|
||||
}
|
||||
function points(history, unit) {
|
||||
if (!history.length) return "0,55 300,55";
|
||||
const peak = unit === "percent" ? Math.max(100, ...history) : Math.max(1, ...history);
|
||||
return history.map((v, i) => `${i * 300 / Math.max(1, history.length - 1)},${55 - v / peak * 50}`).join(" ");
|
||||
}
|
||||
function render(status, record = true) {
|
||||
if (!status || currentPanel !== "overview") return;
|
||||
const now = performance.now();
|
||||
for (const id of names) {
|
||||
const tile = node(id);
|
||||
if (!tile || tile.hidden) { lastCounter.delete(id); continue; }
|
||||
const metric = read(id, status, now, record);
|
||||
const value = metric.value;
|
||||
if (lastUnits.get(id) !== metric.unit) {
|
||||
histories.delete(id);
|
||||
lastUnits.set(id, metric.unit);
|
||||
}
|
||||
const history = histories.get(id) || [];
|
||||
if (record && value !== null) {
|
||||
history.push(value);
|
||||
if (history.length > limit) history.shift();
|
||||
histories.set(id, history);
|
||||
}
|
||||
if (record) lastValue.set(id, value);
|
||||
const field = $(`overview-extra-${id}`);
|
||||
if (field) field.textContent = format(value, metric.unit);
|
||||
const detail = $(`overview-extra-${id}-detail`);
|
||||
if (detail) detail.textContent = metric.detail || t("overviewExtraRecentSamples");
|
||||
$(`overview-extra-${id}-line`)?.setAttribute("points", points(history, metric.unit));
|
||||
}
|
||||
}
|
||||
function reset() { histories.clear(); lastCounter.clear(); lastValue.clear(); lastUnits.clear(); }
|
||||
return { render, reset };
|
||||
})();
|
||||
Reference in new issue
Block a user