This commit is contained in:
Mateusz Gruszczyński committed 2026-10-15 09:37:47 +02:00
1 parent bbfa8cbc3f
commit 2ccc598b12
49 files changed
+4771 -639

No files matched your search

+99 -41
View File
@@ -1,25 +1,69 @@
// Opt-in compact metrics and bounded visualizations. All readings reuse the
// existing Overview live-status payload (no additional requests or timers).
window.rustProxyExtraOverview = (() => {
const limit = 30;
const limit = () => window.rustProxyOverviewSamples?.getLimit?.() ?? 60;
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_cache_hit_rate", "extra_cache_memory", "extra_cold_queue_memory", "extra_cold_storage", "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 bounded = new Set([
"extra_process_fds", "extra_cache_memory", "extra_cold_queue_memory", "extra_cold_storage",
"extra_h1_share", "extra_h2_share", "extra_h3_share",
]);
const histories = new Map(), lastCounter = new Map(), lastValue = new Map();
const lastUnits = new Map(), lastSegments = 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 meter(id, percent) {
const track = $(`${id}-meter`), fill = $(`${id}-meter-fill`);
if (!track || !fill) return;
const valid = positive(percent), boundedPercent = valid === null ? 0 : Math.min(100, valid);
fill.style.width = `${boundedPercent}%`;
if (valid === null) {
track.removeAttribute("aria-valuenow");
track.setAttribute("aria-valuetext", "-");
} else {
track.setAttribute("aria-valuenow", String(boundedPercent));
track.setAttribute("aria-valuetext", `${fmt(valid, 1)}%`);
}
}
function donut(prefix, hits, misses) {
const hit = positive(hits), miss = positive(misses);
const total = hit !== null && miss !== null ? hit + miss : 0;
const share = total > 0 ? hit / total * 100 : 0;
const hitArc = $(`${prefix}-hit-arc`), missArc = $(`${prefix}-miss-arc`);
if (hitArc) hitArc.setAttribute("stroke-dasharray", `${share} ${100 - share}`);
if (missArc) {
missArc.setAttribute("stroke-dasharray", `${100 - share} ${share}`);
missArc.setAttribute("stroke-dashoffset", String(-share));
}
const hitCount = $(`${prefix}-hit-count`), missCount = $(`${prefix}-miss-count`);
if (hitCount) hitCount.textContent = hit === null ? "-" : fmt(hit);
if (missCount) missCount.textContent = miss === null ? "-" : fmt(miss);
const graphic = $(`${prefix}-chart`);
if (graphic) graphic.setAttribute("aria-label", t("overviewCacheHitsMisses")
.replace("{hits}", hit === null ? "-" : fmt(hit))
.replace("{misses}", miss === null ? "-" : fmt(miss)));
}
function elapsedDelta(id, counters, now) {
const old = lastCounter.get(id);
const result = rustProxyRateSampling.difference(old, counters, now, rustProxyRateSampling.cadence("overview_seconds"));
const result = rustProxyRateSampling.difference(lastCounter.get(id), counters, now,
rustProxyRateSampling.cadence("overview_seconds"));
lastCounter.set(id, result.next);
return result.deltas ? result : null;
}
function ramBudget(bytes, budget) {
const used = positive(bytes), maximum = positive(budget);
const percent = maximum > 0 && used !== null ? used / maximum * 100 : null;
return {
value: percent === null ? used : percent,
unit: percent === null ? "bytes" : "percent", meterPercent: percent,
detail: used === null ? "" : `${fmtBytes(used)} / ${maximum > 0 ? fmtBytes(maximum) : t("overviewMeterNoLimit")}`,
};
}
function read(id, status, now, record) {
const m = status.metrics || {}, d = status.system || {}, live = status.live_system || d, c = status.cache || {};
const direct = {
@@ -32,33 +76,28 @@ window.rustProxyExtraOverview = (() => {
extra_active_exchanges: m.active,
};
if (Object.hasOwn(direct, id)) {
const numeric = positive(direct[id]);
const numeric = positive(direct[id]), fdLimit = positive(d.max_fds);
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)}` : ""
value: numeric, unit: id === "extra_process_cpu" ? "percent" : id === "extra_process_rss" ? "bytes"
: id === "extra_response_latency" ? "ms" : "count",
meterPercent: id === "extra_process_fds" && fdLimit > 0 && numeric !== null ? numeric / fdLimit * 100 : null,
detail: id === "extra_process_fds"
? (fdLimit > 0 ? `${t("overviewExtraFdLimit")}: ${fmt(fdLimit)}` : t("overviewMeterNoLimit")) : "",
};
}
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: ""
};
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)}` : ""}`
};
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") return ramBudget(c.resident_bytes, c.hot_limit_bytes);
if (id === "extra_cold_queue_memory") return ramBudget(c.cold_queue_bytes, c.cold_queue_limit_bytes);
if (id === "extra_cold_storage") return ramBudget(c.cold_bytes, c.cold_limit_bytes);
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: "" };
@@ -74,14 +113,18 @@ window.rustProxyExtraOverview = (() => {
})[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: "" };
if (fields.some(v => v === null)) {
lastCounter.delete(id);
return { value: null, unit, detail: "", slices: null };
}
if (!record) return { value: lastValue.get(id) ?? null, unit, detail: "", slices: lastSegments.get(id) || null };
const result = elapsedDelta(id, fields, now);
if (!result) return { value: null, unit, detail: "" };
if (!result) return { value: null, unit, detail: "", slices: null };
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: "" };
return { value: sum > 0 ? Math.min(100, deltas[0] / sum * 100) : null, unit, detail: "",
slices: id === "extra_cache_hit_rate" ? [deltas[0], deltas[1]] : null };
}
function format(value, unit) {
if (value == null) return "-";
@@ -108,20 +151,35 @@ window.rustProxyExtraOverview = (() => {
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 (!bounded.has(id) && id !== "extra_cache_hit_rate") {
const history = histories.get(id) || [];
if (record && value !== null) {
history.push(value);
if (history.length > limit()) history.shift();
histories.set(id, history);
}
$(`overview-extra-${id}-line`)?.setAttribute("points", points(history, metric.unit));
}
if (record) {
lastValue.set(id, value);
if (id === "extra_cache_hit_rate") lastSegments.set(id, metric.slices || null);
}
if (record) lastValue.set(id, value);
const field = $(`overview-extra-${id}`);
if (field) field.textContent = format(value, metric.unit);
if (bounded.has(id)) {
meter(`overview-extra-${id}`, metric.meterPercent ?? (metric.unit === "percent" ? value : null));
} else if (id === "extra_cache_hit_rate") {
const slices = metric.slices || (record ? null : lastSegments.get(id));
donut("extra-cache-ratio", slices?.[0], slices?.[1]);
}
const detail = $(`overview-extra-${id}-detail`);
if (detail) detail.textContent = metric.detail || t("overviewExtraRecentSamples");
$(`overview-extra-${id}-line`)?.setAttribute("points", points(history, metric.unit));
if (detail && id !== "extra_cache_hit_rate") detail.textContent = metric.detail || t("overviewExtraRecentSamples");
}
}
function reset() { histories.clear(); lastCounter.clear(); lastValue.clear(); lastUnits.clear(); }
return { render, reset };
function reset() { histories.clear(); lastCounter.clear(); lastValue.clear(); lastUnits.clear(); lastSegments.clear(); }
window.rustProxyOverviewSamples?.onChange?.(() => {
for (const history of histories.values()) window.rustProxyOverviewSamples.trim(history);
if (typeof latestStatus !== "undefined" && latestStatus && currentPanel === "overview") render(latestStatus, false);
});
return { render, reset, meter, donut };
})();