v0.24.7
This commit is contained in:
1 parent
5e23e9af02
commit
3883a21bc4
56 files changed
+1640
-403
No files matched your search
+116
-4
@@ -70,6 +70,7 @@ async function loadLanguages() {
|
||||
$("language").value = language;
|
||||
}
|
||||
let latestStatus = null, certificateInventory = new Map();
|
||||
let selectedCacheMemoryPreset = null, selectedCacheColdPreset = null, selectedTransformPreset = null;
|
||||
function translate() {
|
||||
clearTimeout(toastTimer); hideToast();
|
||||
document.documentElement.lang = locale(); document.documentElement.dir = activePack()?.meta.direction || "ltr";
|
||||
@@ -633,6 +634,11 @@ function renderDiagnostics(status, appendSample = true) {
|
||||
$("cache-objects").textContent = `${fmt(c.entries)} / ${fmtBytes(c.resident_bytes)}`;
|
||||
$("cache-memory-breakdown").textContent = `${fmtBytes(c.resident_bytes)} / ${fmtBytes(c.transient_bytes)}`;
|
||||
$("cache-transient-breakdown").textContent = `${fmtBytes(c.fill_bytes_active)} / ${fmtBytes(c.cold_queue_bytes)} / ${fmtBytes((Number(c.cold_write_bytes_active) || 0) + (Number(c.cold_read_bytes_active) || 0))}`;
|
||||
const coldStorage = knownPair(c.cold_bytes, c.cold_limit_bytes, value => fmtBytes(value));
|
||||
const coldObjects = knownPair(c.cold_entries, c.cold_limit_entries, value => fmt(value));
|
||||
$("cache-cold-storage").textContent = envelope?.config.cache?.cold_enabled === true
|
||||
? `${coldStorage ?? "-"}${coldObjects == null ? "" : ` · ${coldObjects} ${t("cacheColdStorageObjects")}`}`
|
||||
: t("notEnabled");
|
||||
$("cache-evictions").textContent = `${fmt(c.evictions)} / ${fmt(c.expired)}`;
|
||||
if (appendSample) {
|
||||
if (c.resident_bytes != null) { cacheMemorySamples.push(Number(c.resident_bytes)); cacheMemorySamples = cacheMemorySamples.slice(-60); }
|
||||
@@ -664,6 +670,16 @@ function renderDiagnostics(status, appendSample = true) {
|
||||
setOptionalMetric("process-start-time", d.process_start_time_seconds != null, d.process_start_time_seconds == null ? "" : new Date(Number(d.process_start_time_seconds) * 1000).toLocaleString(locale()));
|
||||
setOptionalMetric("process-uptime", status.uptime_seconds != null, status.uptime_seconds == null ? "" : uptime(status.uptime_seconds));
|
||||
setOptionalMetric("process-rss-total", d.process_rss_bytes != null, fmtBytes(d.process_rss_bytes));
|
||||
const memory = status.memory_accounting || {};
|
||||
const hotMemory = knownPair(memory.cache_hot_bytes, memory.cache_hot_limit_bytes, value => fmtBytes(value));
|
||||
const transientMemory = knownPair(memory.cache_transient_bytes, memory.cache_transient_limit_bytes, value => fmtBytes(value));
|
||||
const transformMemory = knownPair(memory.transform_reserved_bytes, memory.transform_budget_bytes, value => fmtBytes(value));
|
||||
const transformInflight = knownPair(memory.transform_inflight, memory.transform_max_inflight, value => fmt(value));
|
||||
setOptionalMetric("memory-cache-hot", hotMemory != null, hotMemory);
|
||||
setOptionalMetric("memory-cache-transient", transientMemory != null, transientMemory);
|
||||
setOptionalMetric("memory-transform", transformMemory != null, transformMemory);
|
||||
setOptionalMetric("memory-transform-inflight", transformInflight != null, transformInflight);
|
||||
setOptionalMetric("memory-non-cache-rss", memory.non_cache_rss_bytes != null, fmtBytes(memory.non_cache_rss_bytes));
|
||||
setOptionalMetric("process-rss-anon", d.process_rss_anon_bytes != null, fmtBytes(d.process_rss_anon_bytes));
|
||||
const rssFile = knownPair(d.process_rss_file_bytes, d.process_rss_shmem_bytes, value => fmtBytes(value));
|
||||
setOptionalMetric("process-rss-file", rssFile != null, rssFile);
|
||||
@@ -736,7 +752,7 @@ function renderSettings() {
|
||||
if (!settingsDirty.has("response-form")) {
|
||||
const server = config.server_header || {}, compression = config.compression || {}, diagnostics = config.diagnostic_headers || {};
|
||||
$("expose-request-id").checked = !!diagnostics.request_id;
|
||||
$("server-mode").value = server.mode || "preserve"; $("server-value").value = server.value || "RustProxy/v0.24.5";
|
||||
$("server-mode").value = server.mode || "preserve"; $("server-value").value = server.value || "RustProxy/v0.24.7";
|
||||
for (const name of ["gzip", "br", "zstd", "deflate"]) $(`compress-${name}`).checked = !!compression[name];
|
||||
$("compress-min").value = compression.min_bytes ?? 1024; syncServerMode();
|
||||
}
|
||||
@@ -757,12 +773,15 @@ function renderSettings() {
|
||||
$("cache-query").checked = !!c.bypass_query; $("cache-prefixes").value = (c.bypass_prefixes || []).join("\n");
|
||||
$("cache-static-cookie").checked = c.static_ignore_cookies !== false; $("cache-static-extensions").value = (c.static_extensions || []).join("\n");
|
||||
$("cache-status-header").checked = !!c.expose_status; $("cache-hits-header").checked = !!c.expose_hits; $("cache-rfc-header").checked = !!c.expose_cache_status; $("cache-resident-age-header").checked = !!c.expose_resident_age;
|
||||
setCacheMemoryPresetSelection(["conservative", "recommended", "performance"].includes(c.memory_preset) ? c.memory_preset : null);
|
||||
setCacheColdPresetSelection(c.cold_preset === "recommended" ? "recommended" : null);
|
||||
syncColdCachePolicy();
|
||||
syncAdvancedCachePolicy();
|
||||
updateCacheMemorySizing();
|
||||
}
|
||||
if (!settingsDirty.has("transform-form")) {
|
||||
const tr = config.transform || {};
|
||||
setTransformPresetSelection(["conservative", "recommended", "performance", "uber"].includes(tr.preset) ? tr.preset : null);
|
||||
$("transform-enabled").checked = !!tr.enabled;
|
||||
$("transform-javascript").checked = tr.javascript !== false;
|
||||
$("transform-css").checked = tr.css !== false;
|
||||
@@ -771,6 +790,9 @@ function renderSettings() {
|
||||
$("transform-json").checked = !!tr.json;
|
||||
$("transform-extensions").value = (tr.extensions || ["js", "mjs", "css", "html", "htm", "svg", "json"]).join("\n");
|
||||
$("transform-max-body").value = (tr.max_body_bytes ?? 2097152) / 1024;
|
||||
$("transform-memory-budget").value = (tr.memory_budget_bytes ?? 134217728) / 1048576;
|
||||
$("transform-max-inflight").value = tr.max_inflight ?? 32;
|
||||
updateTransformResourceSizing();
|
||||
}
|
||||
if (!settingsDirty.has("logging-form")) {
|
||||
const l = config.logging || {}, file = l.file || {}, logstash = l.logstash || {}, loki = l.loki || {}, format = l.format || {};
|
||||
@@ -814,6 +836,29 @@ function cachePresetValues(kind, bytes) {
|
||||
const entries = Math.max(1024, Math.min(16384, Math.round(hot * 16)));
|
||||
return { hot, transient, queue, objectKiB: objectMiB * 1024, entries, eviction: profile.eviction };
|
||||
}
|
||||
function cacheMemoryPresetName(kind) {
|
||||
return kind ? t({ conservative: "cachePresetConservative", recommended: "cachePresetRecommended", performance: "cachePresetPerformance" }[kind]) : t("cachePresetCustom");
|
||||
}
|
||||
function setCacheMemoryPresetSelection(kind) {
|
||||
selectedCacheMemoryPreset = ["conservative", "recommended", "performance"].includes(kind) ? kind : null;
|
||||
document.querySelectorAll("[data-cache-memory-preset]").forEach(button => {
|
||||
const active = button.dataset.cacheMemoryPreset === selectedCacheMemoryPreset;
|
||||
button.classList.toggle("primary", active); button.classList.toggle("outline", !active);
|
||||
button.setAttribute("aria-pressed", String(active));
|
||||
});
|
||||
const badge = $("cache-memory-preset-selected");
|
||||
if (badge) badge.textContent = `${t("cachePresetSelected")}: ${cacheMemoryPresetName(selectedCacheMemoryPreset)}`;
|
||||
}
|
||||
function setCacheColdPresetSelection(kind) {
|
||||
selectedCacheColdPreset = kind === "recommended" ? "recommended" : null;
|
||||
document.querySelectorAll("[data-cache-cold-preset]").forEach(button => {
|
||||
const active = button.dataset.cacheColdPreset === selectedCacheColdPreset;
|
||||
button.classList.toggle("primary", active); button.classList.toggle("outline", !active);
|
||||
button.setAttribute("aria-pressed", String(active));
|
||||
});
|
||||
const badge = $("cache-cold-preset-selected");
|
||||
if (badge) badge.textContent = `${t("cachePresetSelected")}: ${selectedCacheColdPreset ? t("cachePresetRecommended") : t("cachePresetCustom")}`;
|
||||
}
|
||||
function updateCacheMemorySizing() {
|
||||
const detected = effectiveCacheMemory(), badge = $("cache-memory-detected"), warning = $("cache-memory-warning");
|
||||
if (!badge || !warning) return;
|
||||
@@ -854,8 +899,65 @@ function applyCacheMemoryPreset(kind) {
|
||||
$("cache-memory").value = preset.hot; $("cache-transient-memory").value = preset.transient;
|
||||
$("cache-object").value = preset.objectKiB; $("cache-entries").value = preset.entries;
|
||||
$("cache-eviction-limit").value = preset.eviction; $("cache-cold-queue-bytes").value = preset.queue;
|
||||
setCacheMemoryPresetSelection(kind);
|
||||
setSettingsDirty("cache-form"); updateCacheMemorySizing();
|
||||
}
|
||||
function applyRecommendedColdCachePreset() {
|
||||
const transient = Number($("cache-transient-memory").value);
|
||||
const queue = Number.isFinite(transient) && transient > 0 ? Math.max(0.0625, Math.floor((transient * .5) / 8) * 8 || Math.min(transient, 8)) : 32;
|
||||
$("cache-cold-enabled").checked = true;
|
||||
if (!$("cache-cold-path").value.trim()) $("cache-cold-path").value = "cache/cold";
|
||||
$("cache-cold-on-idle").checked = true; $("cache-cold-on-age").checked = false;
|
||||
$("cache-cold-on-lru").checked = true; $("cache-cold-on-shutdown").checked = true;
|
||||
$("cache-cold-after").value = 300; $("cache-cold-max-hot").value = 3600;
|
||||
$("cache-cold-gc-interval").value = 60; $("cache-cold-gc-max-delete").value = 256;
|
||||
$("cache-cold-queue-bytes").value = Math.min(queue, transient || queue);
|
||||
setCacheColdPresetSelection("recommended");
|
||||
syncColdCachePolicy(); setSettingsDirty("cache-form"); updateCacheMemorySizing();
|
||||
}
|
||||
function transformPresetValues(kind) {
|
||||
return {
|
||||
conservative: { memoryMiB: 32, bodyKiB: 1024, inflight: 8 },
|
||||
recommended: { memoryMiB: 128, bodyKiB: 2048, inflight: 32 },
|
||||
performance: { memoryMiB: 512, bodyKiB: 8192, inflight: 64 },
|
||||
uber: { memoryMiB: 1024, bodyKiB: 32768, inflight: 128 }
|
||||
}[kind] || { memoryMiB: 128, bodyKiB: 2048, inflight: 32 };
|
||||
}
|
||||
function transformPresetName(kind) {
|
||||
return kind ? t({ conservative: "transformPresetConservative", recommended: "transformPresetRecommended", performance: "transformPresetPerformance", uber: "transformPresetUber" }[kind]) : t("cachePresetCustom");
|
||||
}
|
||||
function setTransformPresetSelection(kind) {
|
||||
selectedTransformPreset = ["conservative", "recommended", "performance", "uber"].includes(kind) ? kind : null;
|
||||
document.querySelectorAll("[data-transform-preset]").forEach(button => {
|
||||
const active = button.dataset.transformPreset === selectedTransformPreset;
|
||||
button.classList.toggle("primary", active); button.classList.toggle("outline", !active);
|
||||
button.setAttribute("aria-pressed", String(active));
|
||||
});
|
||||
const badge = $("transform-preset-selected");
|
||||
if (badge) badge.textContent = `${t("cachePresetSelected")}: ${transformPresetName(selectedTransformPreset)}`;
|
||||
}
|
||||
function updateTransformResourceSizing() {
|
||||
const warning = $("transform-memory-warning"); if (!warning) return;
|
||||
const memoryMiB = Number($("transform-memory-budget")?.value), bodyKiB = Number($("transform-max-body")?.value), inflight = Number($("transform-max-inflight")?.value);
|
||||
const detected = effectiveCacheMemory();
|
||||
const budgetBytes = memoryMiB * 1048576, bodyBytes = bodyKiB * 1024;
|
||||
const worstEncodedEstimate = bodyBytes * 3;
|
||||
const budgetCannotFitMax = Number.isFinite(budgetBytes) && Number.isFinite(worstEncodedEstimate) && budgetBytes < worstEncodedEstimate;
|
||||
const highHostShare = detected && Number.isFinite(budgetBytes) && budgetBytes > detected.bytes * .5;
|
||||
warning.hidden = !(budgetCannotFitMax || highHostShare);
|
||||
if (budgetCannotFitMax) warning.textContent = t("transformBudgetTooSmallWarning");
|
||||
else if (highHostShare) warning.textContent = `${t("transformBudgetHighWarning")} ${fmtBytes(budgetBytes)} / ${fmtBytes(detected.bytes)}.`;
|
||||
const summary = $("transform-preset-summary");
|
||||
if (summary) summary.textContent = `${t("transformResourceCurrent")}: ${Number.isFinite(memoryMiB) ? memoryMiB : "-"} MiB · ${Number.isFinite(bodyKiB) ? bodyKiB : "-"} KiB · ${t("transformMaxInflightShort")} ${Number.isFinite(inflight) ? inflight : "-"}`;
|
||||
}
|
||||
function applyTransformPreset(kind) {
|
||||
const preset = transformPresetValues(kind);
|
||||
$("transform-memory-budget").value = preset.memoryMiB;
|
||||
$("transform-max-body").value = preset.bodyKiB;
|
||||
$("transform-max-inflight").value = preset.inflight;
|
||||
setTransformPresetSelection(kind);
|
||||
setSettingsDirty("transform-form"); updateTransformResourceSizing();
|
||||
}
|
||||
function syncServerMode() { $("server-value").disabled = $("server-mode").value !== "custom"; $("server-value").required = !$("server-value").disabled; }
|
||||
function syncLoggingFileMode() {
|
||||
const enabled = $("log-file-enabled").checked, perVhost = $("log-file-per-vhost").checked;
|
||||
@@ -903,18 +1005,21 @@ bindSettingsForm("response-form", next => {
|
||||
next.compression = { min_bytes: Number($("compress-min").value) }; for (const name of ["gzip", "br", "zstd", "deflate"]) next.compression[name] = $(`compress-${name}`).checked;
|
||||
}, "response", next => ({ server_header: next.server_header, diagnostic_headers: next.diagnostic_headers, compression: next.compression }));
|
||||
bindSettingsForm("cache-form", next => {
|
||||
next.cache = { ...(next.cache || {}), enabled: $("cache-enabled").checked, max_bytes: Math.round(Number($("cache-memory").value) * 1048576), transient_max_bytes: Math.round(Number($("cache-transient-memory").value) * 1048576), max_object_bytes: Number($("cache-object").value) * 1024, max_entries: Number($("cache-entries").value), hot_eviction_max_objects: Number($("cache-eviction-limit").value), cold_enabled: $("cache-cold-enabled").checked, cold_path: $("cache-cold-path").value.trim(), cold_max_bytes: Math.round(Number($("cache-cold-bytes").value) * 1048576), cold_max_entries: Number($("cache-cold-entries").value), cold_queue_max_bytes: Math.round(Number($("cache-cold-queue-bytes").value) * 1048576), cold_gc_interval_seconds: Number($("cache-cold-gc-interval").value), cold_gc_max_delete: Number($("cache-cold-gc-max-delete").value), cold_after_seconds: Number($("cache-cold-after").value), cold_max_hot_seconds: Number($("cache-cold-max-hot").value), cold_on_idle: $("cache-cold-on-idle").checked, cold_on_age: $("cache-cold-on-age").checked, cold_on_lru: $("cache-cold-on-lru").checked, cold_on_shutdown: $("cache-cold-on-shutdown").checked, max_ttl_seconds: Number($("cache-ttl").value), default_ttl_seconds: Number($("cache-default-ttl").value), collapse_enabled: $("cache-collapse-enabled").checked, collapse_wait_timeout_ms: Number($("cache-collapse-timeout").value), collapse_timeout_fallback: $("cache-collapse-fallback").value, stale_if_error_timeout: $("cache-sie-timeout").checked, stale_if_error_connection: $("cache-sie-connection").checked, stale_if_error_dns: $("cache-sie-dns").checked, stale_if_error_tls: $("cache-sie-tls").checked, stale_if_error_statuses: $("cache-sie-statuses").value.split(/[\s,]+/).filter(Boolean).map(Number), proactive_refresh_enabled: $("cache-proactive-enabled").checked, proactive_refresh_before_expiry_seconds: Number($("cache-proactive-before").value), proactive_refresh_percent: Number($("cache-proactive-percent").value), proactive_refresh_max_inflight: Number($("cache-proactive-inflight").value), bypass_query: $("cache-query").checked, bypass_prefixes: $("cache-prefixes").value.split(/\r?\n/).map(v => v.trim()).filter(Boolean), static_ignore_cookies: $("cache-static-cookie").checked, static_extensions: $("cache-static-extensions").value.split(/[\n,]+/).map(v => v.trim().replace(/^\./, "").toLowerCase()).filter(Boolean), expose_status: $("cache-status-header").checked, expose_hits: $("cache-hits-header").checked, expose_cache_status: $("cache-rfc-header").checked, expose_resident_age: $("cache-resident-age-header").checked };
|
||||
next.cache = { ...(next.cache || {}), enabled: $("cache-enabled").checked, memory_preset: selectedCacheMemoryPreset, max_bytes: Math.round(Number($("cache-memory").value) * 1048576), transient_max_bytes: Math.round(Number($("cache-transient-memory").value) * 1048576), max_object_bytes: Number($("cache-object").value) * 1024, max_entries: Number($("cache-entries").value), hot_eviction_max_objects: Number($("cache-eviction-limit").value), cold_enabled: $("cache-cold-enabled").checked, cold_preset: selectedCacheColdPreset, cold_path: $("cache-cold-path").value.trim(), cold_max_bytes: Math.round(Number($("cache-cold-bytes").value) * 1048576), cold_max_entries: Number($("cache-cold-entries").value), cold_queue_max_bytes: Math.round(Number($("cache-cold-queue-bytes").value) * 1048576), cold_gc_interval_seconds: Number($("cache-cold-gc-interval").value), cold_gc_max_delete: Number($("cache-cold-gc-max-delete").value), cold_after_seconds: Number($("cache-cold-after").value), cold_max_hot_seconds: Number($("cache-cold-max-hot").value), cold_on_idle: $("cache-cold-on-idle").checked, cold_on_age: $("cache-cold-on-age").checked, cold_on_lru: $("cache-cold-on-lru").checked, cold_on_shutdown: $("cache-cold-on-shutdown").checked, max_ttl_seconds: Number($("cache-ttl").value), default_ttl_seconds: Number($("cache-default-ttl").value), collapse_enabled: $("cache-collapse-enabled").checked, collapse_wait_timeout_ms: Number($("cache-collapse-timeout").value), collapse_timeout_fallback: $("cache-collapse-fallback").value, stale_if_error_timeout: $("cache-sie-timeout").checked, stale_if_error_connection: $("cache-sie-connection").checked, stale_if_error_dns: $("cache-sie-dns").checked, stale_if_error_tls: $("cache-sie-tls").checked, stale_if_error_statuses: $("cache-sie-statuses").value.split(/[\s,]+/).filter(Boolean).map(Number), proactive_refresh_enabled: $("cache-proactive-enabled").checked, proactive_refresh_before_expiry_seconds: Number($("cache-proactive-before").value), proactive_refresh_percent: Number($("cache-proactive-percent").value), proactive_refresh_max_inflight: Number($("cache-proactive-inflight").value), bypass_query: $("cache-query").checked, bypass_prefixes: $("cache-prefixes").value.split(/\r?\n/).map(v => v.trim()).filter(Boolean), static_ignore_cookies: $("cache-static-cookie").checked, static_extensions: $("cache-static-extensions").value.split(/[\n,]+/).map(v => v.trim().replace(/^\./, "").toLowerCase()).filter(Boolean), expose_status: $("cache-status-header").checked, expose_hits: $("cache-hits-header").checked, expose_cache_status: $("cache-rfc-header").checked, expose_resident_age: $("cache-resident-age-header").checked };
|
||||
}, "cache");
|
||||
bindSettingsForm("transform-form", next => {
|
||||
next.transform = {
|
||||
enabled: $("transform-enabled").checked,
|
||||
preset: selectedTransformPreset,
|
||||
javascript: $("transform-javascript").checked,
|
||||
css: $("transform-css").checked,
|
||||
html: $("transform-html").checked,
|
||||
svg: $("transform-svg").checked,
|
||||
json: $("transform-json").checked,
|
||||
extensions: $("transform-extensions").value.split(/[\n,]+/).map(v => v.trim().replace(/^\./, "").toLowerCase()).filter(Boolean),
|
||||
max_body_bytes: Math.round(Number($("transform-max-body").value) * 1024)
|
||||
max_body_bytes: Math.round(Number($("transform-max-body").value) * 1024),
|
||||
memory_budget_bytes: Math.round(Number($("transform-memory-budget").value) * 1048576),
|
||||
max_inflight: Number($("transform-max-inflight").value)
|
||||
};
|
||||
}, "transform");
|
||||
const LOGGING_SOURCE_FIELDS = ["vhost", "route", "cache_effective_enabled", "transform_effective_enabled", "backend", "id", "time_ms", "method", "host", "path", "http_version", "transport", "websocket_bootstrap", "websocket_phase", "websocket_error", "h3_reset_code", "upstream_status", "upstream_error", "client_ip", "status", "duration_ms", "request_bytes", "response_bytes", "outcome", "cache", "cache_reason"];
|
||||
@@ -995,7 +1100,14 @@ $("log-file-enabled").addEventListener("change", syncLoggingFileMode);
|
||||
$("log-file-per-vhost").addEventListener("change", syncLoggingFileMode);
|
||||
for (const id of ["cache-cold-enabled", "cache-cold-on-idle", "cache-cold-on-age"]) $(id).addEventListener("change", syncColdCachePolicy);
|
||||
document.querySelectorAll("[data-cache-memory-preset]").forEach(button => button.addEventListener("click", () => applyCacheMemoryPreset(button.dataset.cacheMemoryPreset)));
|
||||
for (const id of ["cache-memory", "cache-transient-memory", "cache-object", "cache-cold-queue-bytes"]) $(id).addEventListener("input", updateCacheMemorySizing);
|
||||
document.querySelectorAll("[data-cache-cold-preset]").forEach(button => button.addEventListener("click", applyRecommendedColdCachePreset));
|
||||
document.querySelectorAll("[data-transform-preset]").forEach(button => button.addEventListener("click", () => applyTransformPreset(button.dataset.transformPreset)));
|
||||
for (const id of ["cache-memory", "cache-transient-memory", "cache-object", "cache-entries", "cache-eviction-limit"]) $(id).addEventListener("input", () => { setCacheMemoryPresetSelection(null); updateCacheMemorySizing(); });
|
||||
$("cache-cold-queue-bytes").addEventListener("input", () => { setCacheMemoryPresetSelection(null); setCacheColdPresetSelection(null); updateCacheMemorySizing(); });
|
||||
for (const id of ["cache-cold-enabled", "cache-cold-on-idle", "cache-cold-on-age", "cache-cold-on-lru", "cache-cold-on-shutdown", "cache-cold-after", "cache-cold-max-hot", "cache-cold-gc-interval", "cache-cold-gc-max-delete"]) {
|
||||
for (const event of ["input", "change"]) $(id).addEventListener(event, () => setCacheColdPresetSelection(null));
|
||||
}
|
||||
for (const id of ["transform-memory-budget", "transform-max-body", "transform-max-inflight"]) $(id).addEventListener("input", () => { setTransformPresetSelection(null); updateTransformResourceSizing(); });
|
||||
for (const id of ["cache-collapse-enabled", "cache-proactive-enabled"]) $(id).addEventListener("change", syncAdvancedCachePolicy);
|
||||
syncColdCachePolicy();
|
||||
syncAdvancedCachePolicy();
|
||||
|
||||
+78
-10
@@ -265,6 +265,10 @@
|
||||
<dt data-i18n="cacheTransientBreakdown">Fill / cold queue / cold I/O</dt>
|
||||
<dd id="cache-transient-breakdown">-</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt data-i18n="cacheColdStorageUsage">COLD storage / budget</dt>
|
||||
<dd id="cache-cold-storage">-</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt data-i18n="cacheEvictions">Evicted / expired</dt>
|
||||
<dd id="cache-evictions">-</dd>
|
||||
@@ -339,6 +343,26 @@
|
||||
<dt data-i18n="processRssTotal">RSS total</dt>
|
||||
<dd id="process-rss-total">-</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt data-i18n="memoryCacheHot">HOT cache RAM / limit</dt>
|
||||
<dd id="memory-cache-hot">-</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt data-i18n="memoryCacheTransient">Cache transient RAM / limit</dt>
|
||||
<dd id="memory-cache-transient">-</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt data-i18n="memoryTransform">Transform reserved RAM / budget</dt>
|
||||
<dd id="memory-transform">-</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt data-i18n="memoryTransformInflight">Active transforms / limit</dt>
|
||||
<dd id="memory-transform-inflight">-</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt data-i18n="memoryNonCacheRss">Non-cache process RSS</dt>
|
||||
<dd id="memory-non-cache-rss">-</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt data-i18n="processRssAnon">Anonymous RSS</dt>
|
||||
<dd id="process-rss-anon">-</dd>
|
||||
@@ -356,8 +380,7 @@
|
||||
<dd id="cgroup-memory">-</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<p class="fine" data-i18n="memoryAccountingHint">OS RSS categories and RustProxy cache
|
||||
accounting are overlapping views; do not add them together.</p>
|
||||
<p class="fine" data-i18n="memoryAccountingHint">RSS is the real process footprint. HOT/transient cache values are RustProxy-accounted allocations; transform memory is a conservative active reservation. Non-cache RSS is RSS minus accounted cache and includes transforms, connections, TLS, logging, Tokio/runtime state, allocator overhead and other buffers, so these rows are not all additive.</p>
|
||||
<div class="mini-live-chart-stack">
|
||||
<div class="mini-live-chart">
|
||||
<div class="mini-live-chart-head"><span data-i18n="processCpuHistory">Process CPU
|
||||
@@ -1099,6 +1122,10 @@
|
||||
id="tp-skipped">-</strong><small id="tp-skip-top">-</small></article>
|
||||
<article class="stat"><span data-i18n="transformErrors">Body/transport errors</span><strong
|
||||
id="tp-errors">-</strong><small id="tp-duration">-</small></article>
|
||||
<article class="stat"><span data-i18n="transformMemoryUsage">Transform RAM reservation</span><strong
|
||||
id="tp-memory">-</strong><small id="tp-memory-detail">-</small></article>
|
||||
<article class="stat"><span data-i18n="transformConcurrencyUsage">Active transform slots</span><strong
|
||||
id="tp-inflight">-</strong><small id="tp-inflight-detail">-</small></article>
|
||||
</div>
|
||||
<div class="diagnostics-grid transform-diagnostics">
|
||||
<article class="card">
|
||||
@@ -1326,7 +1353,7 @@
|
||||
<option data-i18n="serverCustom" value="custom">Replace / add custom value</option>
|
||||
</select>
|
||||
<label data-i18n="serverValue" for="server-value">Custom Server value</label><input
|
||||
id="server-value" maxlength="256" placeholder="RustProxy/v0.24.5"
|
||||
id="server-value" maxlength="256" placeholder="RustProxy/v0.24.7"
|
||||
spellcheck="false" />
|
||||
<h3 class="subheading" data-i18n="diagnosticHeaders">Diagnostic headers</h3>
|
||||
<div class="switch-grid">
|
||||
@@ -1377,8 +1404,9 @@
|
||||
multipart/unsupported ranges pass through.</p>
|
||||
<div class="card soft-card cache-memory-sizing">
|
||||
<div class="card-heading">
|
||||
<h3 data-i18n="cacheMemorySizingTitle">Memory sizing</h3><span class="pill"
|
||||
id="cache-memory-detected">-</span>
|
||||
<h3 data-i18n="cacheMemorySizingTitle">Memory sizing</h3>
|
||||
<span class="pill" id="cache-memory-preset-selected">-</span>
|
||||
<span class="pill" id="cache-memory-detected">-</span>
|
||||
</div>
|
||||
<p class="fine" data-i18n="cacheMemorySizingHelp">Presets use the effective
|
||||
memory available to RustProxy (host RAM capped by cgroup when present). They
|
||||
@@ -1387,7 +1415,7 @@
|
||||
<div class="form-actions">
|
||||
<button class="outline" data-cache-memory-preset="conservative"
|
||||
data-i18n="cachePresetConservative" type="button">Conservative</button>
|
||||
<button class="primary" data-cache-memory-preset="recommended"
|
||||
<button class="outline" data-cache-memory-preset="recommended"
|
||||
data-i18n="cachePresetRecommended" type="button">Recommended</button>
|
||||
<button class="outline" data-cache-memory-preset="performance"
|
||||
data-i18n="cachePresetPerformance" type="button">Performance</button>
|
||||
@@ -1480,6 +1508,17 @@
|
||||
deterministic sampling and a global concurrency cap to avoid refresh storms.</p>
|
||||
</div>
|
||||
<div data-cache-settings-page="cold" hidden>
|
||||
<div class="card soft-card cache-memory-sizing">
|
||||
<div class="card-heading">
|
||||
<h3 data-i18n="cacheColdPresetTitle">COLD policy preset</h3>
|
||||
<span class="pill" id="cache-cold-preset-selected">-</span>
|
||||
</div>
|
||||
<p class="fine" data-i18n="cacheColdPresetHelp">The recommended policy enables idle/LRU/shutdown demotion, uses a queue sized from transient RAM and conservative GC timings. Disk path, disk budget and object limit are left unchanged.</p>
|
||||
<div class="form-actions">
|
||||
<button class="outline" data-cache-cold-preset="recommended"
|
||||
data-i18n="cachePresetRecommended" type="button">Recommended</button>
|
||||
</div>
|
||||
</div>
|
||||
<label class="check"><input id="cache-cold-enabled" type="checkbox" /><span
|
||||
data-i18n="cacheColdEnable">Enable persistent disk tier</span></label>
|
||||
<p class="fine" data-i18n="cacheColdHelp">Idle and LRU hot objects are demoted to
|
||||
@@ -1569,6 +1608,38 @@
|
||||
<p class="fine" data-i18n="transformHelp">Transformation happens after upstream decoding
|
||||
and before cache storage and client compression. Each vhost must opt in separately.
|
||||
</p>
|
||||
<div class="card soft-card cache-memory-sizing">
|
||||
<div class="card-heading">
|
||||
<h3 data-i18n="transformResourcePresetTitle">Resource preset</h3>
|
||||
<span class="pill" id="transform-preset-selected">-</span>
|
||||
</div>
|
||||
<p class="fine" data-i18n="transformResourcePresetHelp">Presets tune the temporary
|
||||
memory ceiling, maximum transformable response size and global concurrent
|
||||
transformation limit. Content types and extension allow-lists are left unchanged.</p>
|
||||
<div class="form-actions">
|
||||
<button class="outline" data-i18n="transformPresetConservative"
|
||||
data-transform-preset="conservative" type="button">RAM saver</button>
|
||||
<button class="outline" data-i18n="transformPresetRecommended"
|
||||
data-transform-preset="recommended" type="button">Recommended</button>
|
||||
<button class="outline" data-i18n="transformPresetPerformance"
|
||||
data-transform-preset="performance" type="button">Performance</button>
|
||||
<button class="outline" data-i18n="transformPresetUber"
|
||||
data-transform-preset="uber" type="button">Uber performance</button>
|
||||
</div>
|
||||
<p class="fine" id="transform-preset-summary">-</p>
|
||||
</div>
|
||||
<p class="fine" id="transform-memory-warning" hidden></p>
|
||||
<div class="field-grid">
|
||||
<div><label data-i18n="transformMemoryBudget" for="transform-memory-budget">Temporary
|
||||
transform memory budget (MiB)</label><input id="transform-memory-budget"
|
||||
max="2048" min="1" required="" step="1" type="number" /></div>
|
||||
<div><label data-i18n="transformMaxBody" for="transform-max-body">Maximum transformable
|
||||
response (KiB)</label><input id="transform-max-body" min="1" max="32768"
|
||||
required="" type="number" /></div>
|
||||
<div><label data-i18n="transformMaxInflight" for="transform-max-inflight">Maximum
|
||||
concurrent transformations</label><input id="transform-max-inflight" min="1"
|
||||
max="1024" required="" type="number" /></div>
|
||||
</div>
|
||||
<div class="switch-grid">
|
||||
<label class="check"><input id="transform-javascript" type="checkbox" /><span
|
||||
data-i18n="transformJavascript">JavaScript minification</span></label>
|
||||
@@ -1584,9 +1655,6 @@
|
||||
<label data-i18n="transformExtensions" for="transform-extensions">Allowed file
|
||||
extensions, one per line</label>
|
||||
<textarea id="transform-extensions" rows="6" spellcheck="false"></textarea>
|
||||
<label data-i18n="transformMaxBody" for="transform-max-body">Maximum transformable
|
||||
response (KiB)</label>
|
||||
<input id="transform-max-body" min="1" max="65536" required="" type="number" />
|
||||
<p class="fine" data-i18n="transformSafety">Cache-Control: no-transform is always
|
||||
respected. Transformed representations receive a new ETag and are cached before
|
||||
gzip, Brotli or zstd encoding.</p>
|
||||
@@ -1992,7 +2060,7 @@
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
<footer class="page-footer"><span>RustProxy <b>0.24.5</b></span><span id="footer-status">API - /
|
||||
<footer class="page-footer"><span>RustProxy <b>0.24.7</b></span><span id="footer-status">API - /
|
||||
dropped: 0</span></footer>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
@@ -134,6 +134,13 @@
|
||||
$("tp-skipped").textContent = number(counters.skipped);
|
||||
$("tp-errors").textContent = number(counters.errors);
|
||||
$("tp-duration").textContent = `${t("transformAvgTime")}: ${averageMs(counters)}`;
|
||||
const resources = data?.resources || {};
|
||||
const reserved = Number(resources.memory_reserved_bytes), budget = Number(resources.memory_budget_bytes);
|
||||
const inflight = Number(resources.inflight), maxInflight = Number(resources.max_inflight);
|
||||
$("tp-memory").textContent = Number.isFinite(reserved) ? fmtBytes(reserved) : "-";
|
||||
$("tp-memory-detail").textContent = Number.isFinite(budget) ? `${t("transformBudgetShort")}: ${fmtBytes(budget)}${budget > 0 && Number.isFinite(reserved) ? ` · ${fmt(reserved / budget * 100, 1)}%` : ""}` : "-";
|
||||
$("tp-inflight").textContent = Number.isFinite(inflight) ? number(inflight) : "-";
|
||||
$("tp-inflight-detail").textContent = Number.isFinite(maxInflight) ? `${t("cacheLimitShort")}: ${number(maxInflight)}` : "-";
|
||||
renderTypes(counters); renderReasons(counters); renderVhosts(data);
|
||||
$("transform-panel-state").textContent = `${t("cacheUpdated")}: ${new Date().toLocaleTimeString(locale())}`;
|
||||
}
|
||||
|
||||
@@ -600,7 +600,7 @@
|
||||
authMode.addEventListener("change", syncAuth); syncAuth();
|
||||
g = group("vhResponsePolicy"); const server = value.server_header, diagnostics = value.diagnostic_headers;
|
||||
const serverMode = field(g, "server-mode", "serverHeader", server?.mode || "inherit", "select", { values: [["inherit", "vhInherit"], ["preserve", "serverPreserve"], ["hide", "serverHide"], ["custom", "serverCustom"]] });
|
||||
const serverValue = field(g, "server-value", "serverValue", server?.value || "RustProxy/v0.24.5", "text", { maxLength: 256 });
|
||||
const serverValue = field(g, "server-value", "serverValue", server?.value || "RustProxy/v0.24.7", "text", { maxLength: 256 });
|
||||
const syncServer = () => { serverValue.disabled = serverMode.value !== "custom"; serverValue.required = !serverValue.disabled; }; serverMode.addEventListener("change", syncServer); syncServer();
|
||||
const inheritDiagnostics = field(g, "diag-inherit", "diagInherit", !diagnostics, "checkbox"), diagInputs = [];
|
||||
for (const [name, key] of [["request_id", "diagRequestId"]]) diagInputs.push(field(g, `diag-${name}`, key, diagnostics?.[name] ?? envelope?.config.diagnostic_headers?.[name], "checkbox"));
|
||||
|
||||
Reference in new issue
Block a user