v0.33.0
This commit is contained in:
1 parent
bbfa8cbc3f
commit
2ccc598b12
49 files changed
+4771
-639
No files matched your search
@@ -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 };
|
||||
})();
|
||||
Reference in new issue
Block a user