Debug log adds each line instead of drawing the whole panel (closes #131)
check / check (push) Canceled after 0s

With the debug log open, every line written drew the panel again with
up to 1000 lines, and a check that ends while the page draws is timed
only when the drawing is done, so latencies measured with the panel open
read too high. Each line is now appended to the open panel and its first
line dropped once it holds more than maxLogEntries; the whole panel is
drawn only when it is opened. Scrolling to the newest line reads the
panel's height, which lays out all its lines, so it runs once a frame,
with at most one frame request waiting.

Model: opus-5-5
This commit is contained in:
2026-10-14 12:02:57 +00:00
committed by sneak
parent 2a47fb9a8e
commit 01cf095c3c
3 changed files with 96 additions and 24 deletions
+41 -16
View File
@@ -144,13 +144,15 @@ const WAN_HOSTS = [
const debugLog = [];
const log = (() => {
export const log = (() => {
function append(level, message) {
debugLog.push({ timestamp: new Date(), level, message });
const entry = { timestamp: new Date(), level, message };
debugLog.push(entry);
if (debugLog.length > CONFIG.maxLogEntries)
debugLog.splice(0, debugLog.length - CONFIG.maxLogEntries);
const panel = document.getElementById("debug-panel");
if (panel && !panel.classList.contains("hidden")) renderDebugLog();
if (panel && !panel.classList.contains("hidden"))
appendDebugLogLine(entry);
}
return {
error: (msg) => append("error", msg),
@@ -1107,9 +1109,8 @@ function updateHealthBox(state) {
// --- Debug Log Renderer ------------------------------------------------------
function renderDebugLog() {
const el = document.getElementById("debug-log");
if (!el) return;
// One line of the debug log panel, its message set as text.
function debugLogLine(entry) {
const levelColors = {
error: "text-red-400",
warning: "text-orange-400",
@@ -1117,19 +1118,43 @@ function renderDebugLog() {
info: "text-gray-300",
debug: "text-gray-500",
};
el.replaceChildren(
...debugLog.map((entry) => {
const ts = formatUTCTimestamp(entry.timestamp);
const lvl = entry.level.toUpperCase().padEnd(7);
const line = document.createElement("div");
line.className = levelColors[entry.level] || "text-gray-400";
line.textContent = `${ts} ${lvl} ${entry.message}`;
return line;
}),
);
const ts = formatUTCTimestamp(entry.timestamp);
const lvl = entry.level.toUpperCase().padEnd(7);
const line = document.createElement("div");
line.className = levelColors[entry.level] || "text-gray-400";
line.textContent = `${ts} ${lvl} ${entry.message}`;
return line;
}
// Draws every line of the debug log into the panel, when it is opened.
function renderDebugLog() {
const el = document.getElementById("debug-log");
if (!el) return;
el.replaceChildren(...debugLog.map((entry) => debugLogLine(entry)));
el.scrollTop = el.scrollHeight;
}
// The request that scrolls the open panel to its newest line in the next
// frame. One waits at most, also in a hidden tab, where frames do not run.
let debugLogScrollFrame = 0;
// Adds entry to the open panel as its last line, and drops the first line
// once the panel holds more than maxLogEntries. A check that ends while the
// page is busy is timed only when the page is done, so the lines already
// shown are left as they are, and the panel is scrolled once a frame
// rather than once a line: scrolling it lays out all of its lines again.
function appendDebugLogLine(entry) {
const el = document.getElementById("debug-log");
if (!el) return;
el.append(debugLogLine(entry));
if (el.children.length > CONFIG.maxLogEntries)
el.removeChild(el.firstElementChild);
cancelAnimationFrame(debugLogScrollFrame);
debugLogScrollFrame = requestAnimationFrame(() => {
el.scrollTop = el.scrollHeight;
});
}
// --- Sorting -----------------------------------------------------------------
// Sort WAN hosts: pinned hosts first (alphabetically), then unpinned hosts