v0.33.6
This commit is contained in:
1 parent
5dd802ae83
commit
a286355b0e
22 files changed
+447
-70
No files matched your search
@@ -64,6 +64,7 @@ fn admin_app_javascript() -> &'static str {
|
||||
include_str!("web/app/session-resume.js"),
|
||||
include_str!("web/app/refresh.js"),
|
||||
include_str!("web/app/rate-sampling.js"),
|
||||
include_str!("web/app/chart-scales.js"),
|
||||
"const ADMIN_DASHBOARD_WIDGET_REGISTRY = Object.freeze(",
|
||||
include_str!("web/dashboard-widgets.json"),
|
||||
");",
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
// Stable plot ranges: percentages are absolute 0-100; unbounded metrics have
|
||||
// unit-appropriate zero-based floors, expanding only for real higher readings.
|
||||
window.rustProxyChartScale = (() => {
|
||||
const floors = { rate: 100, count: 10, ms: 100, bytes: 64 * 1024 * 1024, "bytes/s": 64 * 1024 };
|
||||
const ceilings = new Map();
|
||||
function peak(key, unit, series) {
|
||||
if (unit === "percent") return 100;
|
||||
const floor = floors[unit] ?? 1;
|
||||
let maximum = floor;
|
||||
for (const values of series) for (const value of values) {
|
||||
if (typeof value === "number" && Number.isFinite(value) && value >= 0)
|
||||
maximum = Math.max(maximum, value);
|
||||
}
|
||||
const magnitude = 10 ** Math.floor(Math.log10(maximum));
|
||||
const tick = [1, 2, 5, 10].find(n => n * magnitude >= maximum) ?? 10;
|
||||
const result = Math.max(ceilings.get(key) ?? 0, tick * magnitude);
|
||||
ceilings.set(key, result);
|
||||
return result;
|
||||
}
|
||||
function reset(prefix) {
|
||||
for (const key of ceilings.keys()) if (key.startsWith(prefix)) ceilings.delete(key);
|
||||
}
|
||||
return { peak, reset };
|
||||
})();
|
||||
@@ -134,10 +134,10 @@ window.rustProxyExtraOverview = (() => {
|
||||
if (unit === "rate") return `${fmt(value, 1)}/s`;
|
||||
return fmt(value);
|
||||
}
|
||||
function points(history, unit) {
|
||||
function points(id, 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(" ");
|
||||
const peak = window.rustProxyChartScale.peak(`extra:${id}`, unit, [history]);
|
||||
return history.map((v, i) => `${i * 300 / Math.max(1, history.length - 1)},${55 - Math.min(v, peak) / peak * 50}`).join(" ");
|
||||
}
|
||||
function render(status, record = true) {
|
||||
if (!status || currentPanel !== "overview") return;
|
||||
@@ -150,6 +150,7 @@ window.rustProxyExtraOverview = (() => {
|
||||
const value = metric.value;
|
||||
if (lastUnits.get(id) !== metric.unit) {
|
||||
histories.delete(id);
|
||||
window.rustProxyChartScale.reset(`extra:${id}`);
|
||||
lastUnits.set(id, metric.unit);
|
||||
}
|
||||
if (!bounded.has(id) && id !== "extra_cache_hit_rate") {
|
||||
@@ -159,7 +160,7 @@ window.rustProxyExtraOverview = (() => {
|
||||
if (history.length > limit()) history.shift();
|
||||
histories.set(id, history);
|
||||
}
|
||||
$(`overview-extra-${id}-line`)?.setAttribute("points", points(history, metric.unit));
|
||||
$(`overview-extra-${id}-line`)?.setAttribute("points", points(id, history, metric.unit));
|
||||
}
|
||||
if (record) {
|
||||
lastValue.set(id, value);
|
||||
@@ -177,7 +178,7 @@ window.rustProxyExtraOverview = (() => {
|
||||
if (detail && id !== "extra_cache_hit_rate") detail.textContent = metric.detail || t("overviewExtraRecentSamples");
|
||||
}
|
||||
}
|
||||
function reset() { histories.clear(); lastCounter.clear(); lastValue.clear(); lastUnits.clear(); lastSegments.clear(); }
|
||||
function reset() { histories.clear(); lastCounter.clear(); lastValue.clear(); lastUnits.clear(); lastSegments.clear(); window.rustProxyChartScale.reset("extra:"); }
|
||||
window.rustProxyOverviewSamples?.onChange?.(() => {
|
||||
for (const history of histories.values()) window.rustProxyOverviewSamples.trim(history);
|
||||
if (typeof latestStatus !== "undefined" && latestStatus && currentPanel === "overview") render(latestStatus, false);
|
||||
|
||||
@@ -6,7 +6,7 @@ window.rustProxyWideOverview = (() => {
|
||||
[s.metrics?.http1_requests, s.metrics?.http2_requests, s.metrics?.http3_requests]
|
||||
},
|
||||
wide_cpu: {
|
||||
unit: "percent", names: ["system", "process"], values: s =>
|
||||
unit: "percent", names: ["system", "process"], max: 100, values: s =>
|
||||
[(s.live_system || s.system)?.cpu_percent, (s.live_system || s.system)?.process_cpu_percent]
|
||||
},
|
||||
wide_memory: {
|
||||
@@ -72,7 +72,8 @@ window.rustProxyWideOverview = (() => {
|
||||
const value = values[i];
|
||||
if (value === null) { drawing = false; continue; }
|
||||
const x = Math.round(600 * i / Math.max(1, count - 1));
|
||||
const y = Math.round(137 - 120 * value / peak);
|
||||
// Fixed-range charts stop at the upper bound; the legend keeps the real reading.
|
||||
const y = Math.round(137 - 120 * Math.min(value, peak) / peak);
|
||||
result += `${drawing ? " L" : " M"}${x} ${y}`;
|
||||
drawing = true;
|
||||
}
|
||||
@@ -98,7 +99,7 @@ window.rustProxyWideOverview = (() => {
|
||||
}
|
||||
last.set(id, values);
|
||||
}
|
||||
const peak = Math.max(1, ...series.flat().filter(n => n !== null));
|
||||
const peak = config.max ?? window.rustProxyChartScale.peak(`wide:${id}`, config.unit, series);
|
||||
config.names.forEach((key, i) => {
|
||||
const value = values[i];
|
||||
const field = $(`overview-wide-${id}-${key}-value`);
|
||||
@@ -111,7 +112,7 @@ window.rustProxyWideOverview = (() => {
|
||||
: format(values[0], config.unit);
|
||||
}
|
||||
}
|
||||
function reset() { history.clear(); baselines.clear(); last.clear(); revision = null; }
|
||||
function reset() { history.clear(); baselines.clear(); last.clear(); revision = null; window.rustProxyChartScale.reset("wide:"); }
|
||||
window.rustProxyOverviewSamples?.onChange?.(() => {
|
||||
for (const series of history.values()) for (const values of series) window.rustProxyOverviewSamples.trim(values);
|
||||
if (typeof latestStatus !== "undefined" && latestStatus && currentPanel === "overview") render(latestStatus, false);
|
||||
|
||||
@@ -87,7 +87,7 @@ window.rustProxyWebOverview = (() => {
|
||||
return output;
|
||||
}
|
||||
function smallPath(values) {
|
||||
const peak = Math.max(1, ...values.filter(v => v != null));
|
||||
const peak = window.rustProxyChartScale.peak("web:php-small", "rate", [values]);
|
||||
return values.filter(value => value !== null).map((value, i, present) => `${i * 300 / Math.max(1, present.length - 1)},${55 - value / peak * 50}`).join(" ");
|
||||
}
|
||||
function ring(id, amounts) {
|
||||
@@ -173,7 +173,8 @@ window.rustProxyWebOverview = (() => {
|
||||
names.forEach((_, i) => { series[i].push(set[id]?.[i] ?? null); window.rustProxyOverviewSamples.trim(series[i]); });
|
||||
histories.set(id, series);
|
||||
}
|
||||
const peak = Math.max(1, ...series.flat().filter(v => v !== null));
|
||||
const unit = id === "www_latency" ? "ms" : id === "www_traffic" ? "bytes/s" : "rate";
|
||||
const peak = window.rustProxyChartScale.peak(`web:${id}`, unit, series);
|
||||
names.forEach((name, i) => {
|
||||
const value = set[id]?.[i];
|
||||
const label = id === "www_latency" ? (value == null ? "-" : `${fmt(value, 1)} ms`)
|
||||
@@ -216,7 +217,7 @@ window.rustProxyWebOverview = (() => {
|
||||
}
|
||||
}
|
||||
}
|
||||
function reset() { histories.clear(); serviceBaselines.clear(); baseline = null; last = null; revision = null; }
|
||||
function reset() { histories.clear(); serviceBaselines.clear(); baseline = null; last = null; revision = null; window.rustProxyChartScale.reset("web:"); }
|
||||
window.rustProxyOverviewSamples.onChange(() => {
|
||||
for (const history of histories.values()) {
|
||||
if (Array.isArray(history[0])) history.forEach(window.rustProxyOverviewSamples.trim);
|
||||
|
||||
@@ -70,12 +70,13 @@
|
||||
function resetLiveChart(selected = scope()) {
|
||||
liveChartScope = selected; liveChartPrevious = null; liveChartPreviousAt = null; liveChartGeneration = null;
|
||||
for (const values of Object.values(liveChartSamples)) values.length = 0;
|
||||
window.rustProxyChartScale.reset("cache-live");
|
||||
for (const id of ["cache-live-hit-line", "cache-live-miss-line", "cache-live-bypass-line"]) $(id)?.setAttribute("points", "0,170 900,170");
|
||||
for (const id of ["cache-live-hit-rate", "cache-live-miss-rate", "cache-live-bypass-rate"]) if ($(id)) $(id).textContent = "0.0/s";
|
||||
if ($("cache-live-chart-value")) $("cache-live-chart-value").textContent = "-";
|
||||
}
|
||||
function redrawLiveChart() {
|
||||
const peak = Math.max(1, ...liveChartSamples.hits, ...liveChartSamples.misses, ...liveChartSamples.bypasses);
|
||||
const peak = window.rustProxyChartScale.peak("cache-live", "rate", Object.values(liveChartSamples));
|
||||
$("cache-live-hit-line")?.setAttribute("points", sparklinePoints(liveChartSamples.hits, 900, 180, 10, peak));
|
||||
$("cache-live-miss-line")?.setAttribute("points", sparklinePoints(liveChartSamples.misses, 900, 180, 10, peak));
|
||||
$("cache-live-bypass-line")?.setAttribute("points", sparklinePoints(liveChartSamples.bypasses, 900, 180, 10, peak));
|
||||
|
||||
+16
-16
@@ -651,7 +651,7 @@
|
||||
</div>
|
||||
<svg preserveAspectRatio="none" class="overview-wide-svg" viewBox="0 0 600 150" role="img"
|
||||
aria-label="HTTP/1.1 · HTTP/2 · HTTP/3 traffic">
|
||||
<path class="chart-grid" d="M0 37H600 M0 75H600 M0 113H600"></path>
|
||||
<path class="chart-grid" d="M0 47H600 M0 77H600 M0 107H600"></path>
|
||||
<path class="overview-wide-series overview-wide-series-0"
|
||||
id="overview-wide-wide_protocol_rates-h1-line" d=""></path>
|
||||
<path class="overview-wide-series overview-wide-series-1"
|
||||
@@ -675,7 +675,7 @@
|
||||
</div>
|
||||
<svg preserveAspectRatio="none" class="overview-wide-svg" viewBox="0 0 600 150" role="img"
|
||||
aria-label="System and process CPU">
|
||||
<path class="chart-grid" d="M0 37H600 M0 75H600 M0 113H600"></path>
|
||||
<path class="chart-grid" d="M0 47H600 M0 77H600 M0 107H600"></path>
|
||||
<path class="overview-wide-series overview-wide-series-0"
|
||||
id="overview-wide-wide_cpu-system-line" d=""></path>
|
||||
<path class="overview-wide-series overview-wide-series-1"
|
||||
@@ -697,7 +697,7 @@
|
||||
</div>
|
||||
<svg preserveAspectRatio="none" class="overview-wide-svg" viewBox="0 0 600 150" role="img"
|
||||
aria-label="Process RAM and cache memory">
|
||||
<path class="chart-grid" d="M0 37H600 M0 75H600 M0 113H600"></path>
|
||||
<path class="chart-grid" d="M0 47H600 M0 77H600 M0 107H600"></path>
|
||||
<path class="overview-wide-series overview-wide-series-0"
|
||||
id="overview-wide-wide_memory-process-line" d=""></path>
|
||||
<path class="overview-wide-series overview-wide-series-1"
|
||||
@@ -720,7 +720,7 @@
|
||||
</div>
|
||||
<svg preserveAspectRatio="none" class="overview-wide-svg" viewBox="0 0 600 150" role="img"
|
||||
aria-label="Cache hits / misses per second">
|
||||
<path class="chart-grid" d="M0 37H600 M0 75H600 M0 113H600"></path>
|
||||
<path class="chart-grid" d="M0 47H600 M0 77H600 M0 107H600"></path>
|
||||
<path class="overview-wide-series overview-wide-series-0"
|
||||
id="overview-wide-wide_cache_activity-hits-line" d=""></path>
|
||||
<path class="overview-wide-series overview-wide-series-1"
|
||||
@@ -741,7 +741,7 @@
|
||||
</div>
|
||||
<svg preserveAspectRatio="none" class="overview-wide-svg" viewBox="0 0 600 150" role="img"
|
||||
aria-label="Connections and WebSocket tunnels">
|
||||
<path class="chart-grid" d="M0 37H600 M0 75H600 M0 113H600"></path>
|
||||
<path class="chart-grid" d="M0 47H600 M0 77H600 M0 107H600"></path>
|
||||
<path class="overview-wide-series overview-wide-series-0"
|
||||
id="overview-wide-wide_connections-open-line" d=""></path>
|
||||
<path class="overview-wide-series overview-wide-series-1"
|
||||
@@ -764,7 +764,7 @@
|
||||
</div>
|
||||
<svg preserveAspectRatio="none" class="overview-wide-svg" viewBox="0 0 600 150" role="img"
|
||||
aria-label="Backend availability over time">
|
||||
<path class="chart-grid" d="M0 37H600 M0 75H600 M0 113H600"></path>
|
||||
<path class="chart-grid" d="M0 47H600 M0 77H600 M0 107H600"></path>
|
||||
<path class="overview-wide-series overview-wide-series-0"
|
||||
id="overview-wide-wide_backend_health-up-line" d=""></path>
|
||||
<path class="overview-wide-series overview-wide-series-1"
|
||||
@@ -786,7 +786,7 @@
|
||||
</div>
|
||||
<svg preserveAspectRatio="none" class="overview-wide-svg" viewBox="0 0 600 150" role="img"
|
||||
aria-label="Response and backend probe latency">
|
||||
<path class="chart-grid" d="M0 37H600 M0 75H600 M0 113H600"></path>
|
||||
<path class="chart-grid" d="M0 47H600 M0 77H600 M0 107H600"></path>
|
||||
<path class="overview-wide-series overview-wide-series-0"
|
||||
id="overview-wide-wide_latency-response-line" d=""></path>
|
||||
<path class="overview-wide-series overview-wide-series-1"
|
||||
@@ -809,7 +809,7 @@
|
||||
</div>
|
||||
<svg preserveAspectRatio="none" class="overview-wide-svg" viewBox="0 0 600 150" role="img"
|
||||
data-i18n-aria="overviewWideTransformActivity" aria-label="Transformation activity">
|
||||
<path class="chart-grid" d="M0 37H600 M0 75H600 M0 113H600"></path>
|
||||
<path class="chart-grid" d="M0 47H600 M0 77H600 M0 107H600"></path>
|
||||
<path class="overview-wide-series overview-wide-series-0"
|
||||
id="overview-wide-wide_transform_activity-applied-line" d=""></path>
|
||||
<path class="overview-wide-series overview-wide-series-1"
|
||||
@@ -842,7 +842,7 @@
|
||||
</div>
|
||||
<svg preserveAspectRatio="none" class="overview-wide-svg" viewBox="0 0 600 150" role="img"
|
||||
data-i18n-aria="overviewWideCompressionActivity" aria-label="Compression activity">
|
||||
<path class="chart-grid" d="M0 37H600 M0 75H600 M0 113H600"></path>
|
||||
<path class="chart-grid" d="M0 47H600 M0 77H600 M0 107H600"></path>
|
||||
<path class="overview-wide-series overview-wide-series-0"
|
||||
id="overview-wide-wide_compression_activity-gzip-line" d=""></path>
|
||||
<path class="overview-wide-series overview-wide-series-1"
|
||||
@@ -954,7 +954,7 @@
|
||||
</div>
|
||||
<svg preserveAspectRatio="none" class="overview-wide-svg" viewBox="0 0 600 150" role="img"
|
||||
aria-label="Web Server request rate" data-i18n-aria="webMetricRequests">
|
||||
<path class="chart-grid" d="M0 37H600 M0 75H600 M0 113H600"></path>
|
||||
<path class="chart-grid" d="M0 47H600 M0 77H600 M0 107H600"></path>
|
||||
<path class="overview-wide-series overview-wide-series-0" id="www_requests-all-line"
|
||||
d=""></path>
|
||||
<path class="overview-wide-series overview-wide-series-1" id="www_requests-php-line"
|
||||
@@ -975,7 +975,7 @@
|
||||
</div>
|
||||
<svg preserveAspectRatio="none" class="overview-wide-svg" viewBox="0 0 600 150" role="img"
|
||||
aria-label="Web Server header latency" data-i18n-aria="webMetricLatency">
|
||||
<path class="chart-grid" d="M0 37H600 M0 75H600 M0 113H600"></path>
|
||||
<path class="chart-grid" d="M0 47H600 M0 77H600 M0 107H600"></path>
|
||||
<path class="overview-wide-series overview-wide-series-0" id="www_latency-web-line"
|
||||
d=""></path>
|
||||
<path class="overview-wide-series overview-wide-series-1" id="www_latency-php-line"
|
||||
@@ -996,7 +996,7 @@
|
||||
</div>
|
||||
<svg preserveAspectRatio="none" class="overview-wide-svg" viewBox="0 0 600 150" role="img"
|
||||
aria-label="PHP FastCGI failures" data-i18n-aria="webMetricFailures">
|
||||
<path class="chart-grid" d="M0 37H600 M0 75H600 M0 113H600"></path>
|
||||
<path class="chart-grid" d="M0 47H600 M0 77H600 M0 107H600"></path>
|
||||
<path class="overview-wide-series overview-wide-series-0" id="www_failures-timeout-line"
|
||||
d=""></path>
|
||||
<path class="overview-wide-series overview-wide-series-1"
|
||||
@@ -1027,7 +1027,7 @@
|
||||
</div>
|
||||
<svg preserveAspectRatio="none" class="overview-wide-svg" viewBox="0 0 600 150" role="img"
|
||||
aria-label="Web Server body byte rate" data-i18n-aria="webMetricTraffic">
|
||||
<path class="chart-grid" d="M0 37H600 M0 75H600 M0 113H600"></path>
|
||||
<path class="chart-grid" d="M0 47H600 M0 77H600 M0 107H600"></path>
|
||||
<path class="overview-wide-series overview-wide-series-0" id="www_traffic-nonphp-line"
|
||||
d=""></path>
|
||||
<path class="overview-wide-series overview-wide-series-1" id="www_traffic-php-line"
|
||||
@@ -1048,7 +1048,7 @@
|
||||
</div>
|
||||
<svg preserveAspectRatio="none" class="overview-wide-svg" viewBox="0 0 600 150" role="img"
|
||||
aria-label="Web Server HTTP statuses" data-i18n-aria="webMetricStatusTrend">
|
||||
<path class="chart-grid" d="M0 37H600 M0 75H600 M0 113H600"></path>
|
||||
<path class="chart-grid" d="M0 47H600 M0 77H600 M0 107H600"></path>
|
||||
<path class="overview-wide-series overview-wide-series-0" id="www_status_trend-2xx-line"
|
||||
d=""></path>
|
||||
<path class="overview-wide-series overview-wide-series-1" id="www_status_trend-3xx-line"
|
||||
@@ -2293,7 +2293,7 @@
|
||||
<svg aria-label="Live cache activity" data-i18n-aria="cacheLiveChartTitle"
|
||||
id="cache-live-activity-chart" role="img" viewBox="0 0 900 180"
|
||||
preserveAspectRatio="none">
|
||||
<path class="chart-grid" d="M0 45H900 M0 90H900 M0 135H900"></path>
|
||||
<path class="chart-grid" d="M0 50H900 M0 90H900 M0 130H900"></path>
|
||||
<polyline class="function-live-line cache-hit-line" id="cache-live-hit-line"
|
||||
points="0,170 900,170"></polyline>
|
||||
<polyline class="function-live-line cache-miss-line" id="cache-live-miss-line"
|
||||
@@ -2446,7 +2446,7 @@
|
||||
<svg aria-label="Live transformation activity" data-i18n-aria="transformLiveChartTitle"
|
||||
id="transform-live-activity-chart" role="img" viewBox="0 0 900 180"
|
||||
preserveAspectRatio="none">
|
||||
<path class="chart-grid" d="M0 45H900 M0 90H900 M0 135H900"></path>
|
||||
<path class="chart-grid" d="M0 50H900 M0 90H900 M0 130H900"></path>
|
||||
<polyline class="function-live-line transform-applied-line"
|
||||
id="transform-live-applied-line" points="0,170 900,170"></polyline>
|
||||
<polyline class="function-live-line transform-cache-line" id="transform-live-cache-line"
|
||||
|
||||
@@ -7177,7 +7177,7 @@ body[data-density=compact] .page-footer {
|
||||
.function-live-chart svg {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: calc(clamp(180px, 22vw, 270px));
|
||||
height: 180px;
|
||||
overflow: visible
|
||||
}
|
||||
|
||||
@@ -7270,9 +7270,6 @@ body[data-density=compact] .page-footer {
|
||||
white-space: normal
|
||||
}
|
||||
|
||||
.function-live-chart svg {
|
||||
height: 190px
|
||||
}
|
||||
|
||||
.function-live-chart-footer {
|
||||
align-items: flex-start;
|
||||
@@ -10889,7 +10886,7 @@ html[data-dashboard-density=ultra] #panel-overview .dashboard-overview-grid>.car
|
||||
#panel-overview .overview-wide-svg {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: calc(clamp(125px, 13vw, 190px));
|
||||
height: 125px;
|
||||
margin-block: 13px 9px;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,12 +22,13 @@
|
||||
function resetLiveChart(selected = scope()) {
|
||||
liveChartScope = selected; liveChartPrevious = null; liveChartPreviousAt = null; liveChartGeneration = null;
|
||||
for (const values of Object.values(liveChartSamples)) values.length = 0;
|
||||
window.rustProxyChartScale.reset("transform-live");
|
||||
for (const id of ["transform-live-applied-line", "transform-live-cache-line", "transform-live-skipped-line", "transform-live-error-line"]) $(id)?.setAttribute("points", "0,170 900,170");
|
||||
for (const id of ["transform-live-applied-rate", "transform-live-cache-rate", "transform-live-skipped-rate", "transform-live-error-rate"]) if ($(id)) $(id).textContent = "0.0/s";
|
||||
if ($("transform-live-chart-value")) $("transform-live-chart-value").textContent = "-";
|
||||
}
|
||||
function redrawLiveChart() {
|
||||
const peak = Math.max(1, ...liveChartSamples.applied, ...liveChartSamples.cache_hits, ...liveChartSamples.skipped, ...liveChartSamples.errors);
|
||||
const peak = window.rustProxyChartScale.peak("transform-live", "rate", Object.values(liveChartSamples));
|
||||
$("transform-live-applied-line")?.setAttribute("points", sparklinePoints(liveChartSamples.applied, 900, 180, 10, peak));
|
||||
$("transform-live-cache-line")?.setAttribute("points", sparklinePoints(liveChartSamples.cache_hits, 900, 180, 10, peak));
|
||||
$("transform-live-skipped-line")?.setAttribute("points", sparklinePoints(liveChartSamples.skipped, 900, 180, 10, peak));
|
||||
|
||||
Reference in new issue
Block a user