Statistics page: the statistics database's size, and a fullness bar on the disk tiles
The server section shows the statistics database's size (with its -wal and -shm) and how many answers the query log holds, linking to the dashboard's Storage panel; the disk tiles get the same bar as the dashboard. GET /stats/server has database {path, bytes, query_log_rows}.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
01ec37b9b2
commit
1b102a78f6
8 files changed
+78
-13
No files matched your search
@@ -145,7 +145,7 @@ export async function render(el, params, query) {
|
||||
rtt.length ? listCard("Upstream response time", "how long other servers took to answer named's recursive queries", barList(rtt)) : null,
|
||||
b.blocklist.length ? listCard("Blocked by", "which of your rules and blocklists blocked queries", barList(b.blocklist, { label: (k) => (k === "rules" ? "your rules" : k), href: ex((k) => ({ blocked: k })) || (() => "#/blocking") })) : null));
|
||||
|
||||
parts.push(...serverSection(data.server, complete(data.gauges), rangeLabel));
|
||||
parts.push(...serverSection(data.server, complete(data.gauges), rangeLabel, status));
|
||||
el.classList.remove("refreshing");
|
||||
mount(el, parts);
|
||||
scheduleRefresh(el, params, query, gen);
|
||||
@@ -223,7 +223,7 @@ const gaugeKeys = ["g:named:rss", "g:named:mem", "g:cache:mem", "g:named:cpu"];
|
||||
|
||||
// serverSection shows named's process, cache, clients, the host and the
|
||||
// disks now, and named's memory and CPU over time.
|
||||
function serverSection(sv, gauges, rangeLabel) {
|
||||
function serverSection(sv, gauges, rangeLabel, status) {
|
||||
const srv = (sv && sv.server) || {};
|
||||
const named = (sv && sv.named) || {};
|
||||
const host = srv.host || {};
|
||||
@@ -243,7 +243,8 @@ function serverSection(sv, gauges, rangeLabel) {
|
||||
tc ? tile("TCP clients", tc[0], tc[1]) : null,
|
||||
tile("Up since", srv.boot_time ? relTime(srv.boot_time).replace(" ago", "") : "–", srv.config_time ? "named started " + fmtTime(srv.boot_time) + " · reconfigured " + relTime(srv.config_time) : ""),
|
||||
host.mem_total ? tile("Host memory", pct((host.mem_total - host.mem_available) / host.mem_total), "of " + bytes(host.mem_total) + " in use · load " + (host.load || []).map((x) => x.toFixed(2)).join(" ")) : null,
|
||||
...((sv && sv.disks) || []).map((d) => tile("Disk space", bytes(d.free) + " free", h("span", { title: d.path }, "of " + bytes(d.total) + ", for " + d.holds.join(", "))))));
|
||||
sv && sv.database ? dbTile(sv.database, status) : null,
|
||||
...((sv && sv.disks) || []).map(diskTile)));
|
||||
if (sv && sv.named_error) out.push(h("div", { class: "msg info" }, "Client counts need rndc: " + sv.named_error));
|
||||
// Gauges over time: averages, -1 where there was no sample.
|
||||
const series = (key) => ((gauges.series || []).find((x) => x.key === key) || { values: gauges.times.map(() => -1) }).values.map((v) => (v < 0 ? null : v));
|
||||
@@ -312,3 +313,25 @@ function disabledPanel() {
|
||||
function exploreSince(since) {
|
||||
return rangeSecs[since] > 7 * 86400 ? "7d" : since;
|
||||
}
|
||||
|
||||
// dbTile is the statistics database's size: what the statistics cost on
|
||||
// disk (the dashboard's Storage panel has all of Jarl's databases).
|
||||
function dbTile(db, status) {
|
||||
const keep = ((status || {}).retention || {}).queries;
|
||||
const sub = db.query_log_rows != null
|
||||
? "the query log holds " + compact(db.query_log_rows) + " answers (" + keep + ")"
|
||||
: "counters and top lists; no query log";
|
||||
return h("a", { class: "card link", href: "#/", title: db.path + " · all of Jarl's databases: Dashboard → Storage" },
|
||||
h("div", { class: "label" }, "Statistics database"), h("div", { class: "value" }, bytes(db.bytes)), h("div", { class: "sub" }, sub));
|
||||
}
|
||||
|
||||
// diskTile is a disk's free space, with a bar of how full it is.
|
||||
function diskTile(d) {
|
||||
const u = d.total ? (d.total - d.free) / d.total : 0;
|
||||
return h("div", { class: "card", title: d.path },
|
||||
h("div", { class: "label" }, "Disk space"),
|
||||
h("div", { class: "value" }, bytes(d.free) + " free"),
|
||||
h("div", { class: "disk-bar", role: "img", "aria-label": Math.round(u * 100) + "% used" },
|
||||
h("div", { class: "seg other" + (u > 0.9 ? " full" : ""), style: { width: u * 100 + "%" } })),
|
||||
h("div", { class: "sub" }, h("span", { class: u > 0.9 ? "warn-text" : "" }, Math.round(u * 100) + "% of " + bytes(d.total) + " used"), ", for " + d.holds.join(", ")));
|
||||
}
|
||||
@@ -613,3 +613,4 @@ table.recent-queries td.oneline-cell { max-width: 40ch; white-space: nowrap; ove
|
||||
.swatch { display: inline-block; width: 10px; height: 10px; border-radius: 2px; vertical-align: -1px; }
|
||||
.swatch.db { background: var(--accent); }
|
||||
.swatch.other { background: var(--muted); opacity: 0.45; }
|
||||
.card .disk-bar { margin: 6px 0 4px; height: 8px; }
|
||||
Reference in new issue
Block a user