diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/api/dashboard/dashboard.html | 38 |
1 files changed, 35 insertions, 3 deletions
diff --git a/src/api/dashboard/dashboard.html b/src/api/dashboard/dashboard.html index 94e3dfb..876c386 100644 --- a/src/api/dashboard/dashboard.html +++ b/src/api/dashboard/dashboard.html @@ -32,6 +32,8 @@ header h1 { font-size: 16px; margin: 0; } #connection { margin-left: auto; color: var(--muted); } #clock-warning, #peers .clock-off { color: var(--warn); } + /* A minute's bar each, the last 15: a link's trend at a glance. */ + #peers .spark { font-family: ui-monospace, monospace; letter-spacing: 0; opacity: 0.7; } #connection.live { color: var(--ok); } #connection.down { color: var(--bad); } /* A dot in the status's colour that breathes once with every event. */ @@ -429,9 +431,11 @@ function renderPeers() { const table = document.getElementById("peers"); const headers = { reaches: "How many members besides this node it reaches (an active " + "session with each), as it said; +: those of them this node doesn't reach itself (it " + - "is a way to them)" }; - const rows = [el("tr", {}, ...["peer", "status", "seen", "via", "rtt", "clock", "neighbour", - "reaches", "same epoch"] + "is a way to them)", hop: "How long its sync messages take to come, by its clock and " + + "this node's (its offset taken off): this minute's mean, and the last 15 minutes' as " + + "a line; good to half the round trip, but the trend exactly" }; + const rows = [el("tr", {}, ...["peer", "status", "seen", "via", "rtt", "hop", "clock", + "neighbour", "reaches", "same epoch"] .map(h => el("th", { title: headers[h] || "" }, h)))]; // Whom this node reaches, to tell those a peer reaches and it doesn't. const ours = new Set(state.peers.localReaches || []); @@ -450,6 +454,7 @@ function renderPeers() { el("td", {}, age(aged("lastSeenSecsAgo", peer.lastSeenSecsAgo))), el("td", { class: "id" }, via), el("td", {}, rtt), + hopCell(peer.hopDelay), // Its clock against this node's, flagged beyond the limit (`--clock-skew-warn`). el("td", { class: clockOff(peer.clock) ? "clock-off" : "", title: peer.clock ? "ahead of this node's by " + peer.clock.offsetMs + " ms, give or take " + @@ -469,6 +474,33 @@ function renderPeers() { ? (rows[8].offsetTop + rows[8].offsetHeight) + "px" : ""; } +// How long a peer's sync messages take to come (`hopDelay`): the latest minute's mean, +// and the last 15 minutes' as a line of bars (a minute without messages blank), each +// figure in the tooltip. +function hopCell(hop) { + if (!hop) return el("td", { title: "no sync message from it yet while its clock was known" }, ""); + const minutes = hop.byMinuteMs || []; + const known = minutes.filter(ms => typeof ms === "number"); + const latest = known.length ? known[known.length - 1] : null; + const low = Math.min(...known), high = Math.max(...known); + const bars = "\u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588"; + const line = minutes.map(ms => typeof ms !== "number" ? " " + : bars[high > low ? Math.round((ms - low) / (high - low) * (bars.length - 1)) : 0]).join(""); + const within = ms => ms === null || ms === undefined ? "beyond the last bucket" : "within " + ms + " ms"; + const title = [ + hop.count + " messages since this node started, mean " + hop.meanMs + " ms", + "half " + within(hop.halfWithinMs) + ", 99% " + within(hop.p99WithinMs), + hop.halfRttMs !== null && hop.halfRttMs !== undefined + ? "half the round trip: " + hop.halfRttMs + " ms (beyond it: waiting in queues, or the clock offset's error)" + : "no recent round trip", + hop.belowZero ? hop.belowZero + " took less than nothing by the clocks (the offset's error)" : "", + "the last 15 minutes' means, oldest first: " + + minutes.map(ms => typeof ms === "number" ? ms : "–").join(", "), + ].filter(Boolean).join("\n"); + return el("td", { title }, + latest === null ? "" : latest + " ms ", el("span", { class: "spark" }, line)); +} + // Whom a peer reaches (`reaches`, as it said; null: it hasn't said in this session), as // a count, and those of them this node doesn't reach (`ours`), marked: the peer is a way // to them. Each by name in the tooltip. |
