v0.116.0: observability pass — always-on debug ring + leveled sweep + agent tab + self-log pull — MinAgent: 0.81.0

Capture layer: LogBuffer always exists; logger = MultiWriter(LevelFilterWriter
(stdout, logging.level), ring) so DEBUG detail exists remotely without a config
flip while docker logs keep respecting the level. New internal/logx leveled
helpers. Report ACK gains controller_log_requested (additive); next report
ships controller_log_tail (128KB, consume-once, app-tail wire byte-compatible).
Debug page: Vezérlő|Ügynök tabs; agent tab proxies agent /debug/logs with the
pre-0.83 notice on typed 404. Sweep: netstorage_job phases, netprobe, handler
validation refusals + orphan WARN, SupportsWithSource gate line, agentapi
per-call DEBUG, migrate phase lines, tier2/offbox unswallowed persists.
Red-proofs: filter-disabled, drain-removed, dropped-phase-line all FAIL.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
This commit is contained in:
2026-07-11 16:45:57 +02:00
parent 647116480a
commit 26a43708b7
25 changed files with 797 additions and 31 deletions
+46 -1
View File
@@ -212,6 +212,10 @@
<span class="section-toggle"></span>
</div>
<div class="card-body debug-section-body" style="display:none">
<div class="debug-log-filters" style="margin-bottom:.5rem">
<button class="btn btn-xs debug-log-source active" id="log-tab-controller" onclick="setLogSource('controller',this)">Vezérlő</button>
<button class="btn btn-xs debug-log-source" id="log-tab-agent" onclick="setLogSource('agent',this)">Ügynök</button>
</div>
<div class="debug-log-controls">
<div class="debug-log-filters">
<button class="btn btn-xs debug-log-filter active" data-level="DEBUG" onclick="setLogLevel('DEBUG',this)">DEBUG</button>
@@ -583,15 +587,24 @@ function triggerDR() {
});
}
// ── Section 8: Log viewer ──
// ── Section 8: Log viewer (Vezérlő | Ügynök tabs — v0.116.0) ──
var currentLogLevel = 'DEBUG';
var currentLogSource = 'controller';
var lastLogTimestamp = '';
var LOG_LEVEL_PRIORITY = {DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3};
function setLogLevel(level, btn) {
currentLogLevel = level;
document.querySelectorAll('.debug-log-filter').forEach(function(b) { b.classList.remove('active'); });
btn.classList.add('active');
refreshLogs();
}
function setLogSource(source, btn) {
currentLogSource = source;
document.querySelectorAll('.debug-log-source').forEach(function(b) { b.classList.remove('active'); });
btn.classList.add('active');
clearLogDisplay();
refreshLogs();
}
function initLogViewer() {
refreshLogs();
if (document.getElementById('log-auto-refresh').checked) {
@@ -606,6 +619,7 @@ function toggleLogAutoRefresh() {
}
}
function refreshLogs(append) {
if (currentLogSource === 'agent') { refreshAgentLogs(); return; }
var url = '/api/debug/logs?level=' + currentLogLevel + '&limit=500';
if (append && lastLogTimestamp) url += '&after=' + encodeURIComponent(lastLogTimestamp);
fetch(url, {headers: csrfHeaders()}).then(function(r){return r.json()}).then(function(data) {
@@ -630,6 +644,37 @@ function refreshLogs(append) {
document.getElementById('log-count').textContent = viewer.children.length + ' / ' + total + ' bejegyzés';
}).catch(function(){});
}
// The agent tab: full refresh each poll (the agent ring is small), client-side level
// filter. A pre-0.83 agent (unsupported) renders the notice instead of an error.
function refreshAgentLogs() {
fetch('/api/debug/agent-logs', {headers: csrfHeaders()}).then(function(r){return r.json()}).then(function(data) {
var viewer = document.getElementById('log-viewer');
viewer.innerHTML = '';
if (!data.ok) {
viewer.innerHTML = '<div class="debug-log-entry debug-log-warn">' + escapeHtml(data.error || 'Hiba') + '</div>';
document.getElementById('log-count').textContent = '';
return;
}
if (data.data && data.data.unsupported) {
viewer.innerHTML = '<div class="debug-log-entry">' + escapeHtml(data.data.notice) + '</div>';
document.getElementById('log-count').textContent = '';
return;
}
var entries = (data.data && data.data.entries) || [];
var total = (data.data && data.data.total) || 0;
var min = LOG_LEVEL_PRIORITY[currentLogLevel] || 0;
entries.forEach(function(e) {
if ((LOG_LEVEL_PRIORITY[e.level] || 0) < min) return;
var div = document.createElement('div');
div.className = 'debug-log-entry debug-log-' + e.level.toLowerCase();
var ts = e.timestamp ? fmtTime(e.timestamp) : '';
div.innerHTML = '<span class="text-muted">' + ts + '</span> <span class="debug-log-level">[' + e.level + ']</span> ' + escapeHtml(e.message);
viewer.appendChild(div);
});
viewer.scrollTop = viewer.scrollHeight;
document.getElementById('log-count').textContent = viewer.children.length + ' / ' + total + ' bejegyzés';
}).catch(function(){});
}
function clearLogDisplay() {
document.getElementById('log-viewer').innerHTML = '';
document.getElementById('log-count').textContent = '';