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 result = rustProxyRateSampling.difference(old, counters, now, rustProxyRateSampling.cadence("overview_seconds")); lastCounter.set(id, result.next); return result.deltas ? result : null; } function read(id, status, now, record) { const m = status.metrics || {}, d = status.system || {}, live = status.live_system || d, c = status.cache || {}; const direct = { extra_process_cpu: live.process_cpu_percent, extra_process_rss: live.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 }; })();