diff --git a/web/static/js/app.js b/web/static/js/app.js index 200070b..fcfb301 100644 --- a/web/static/js/app.js +++ b/web/static/js/app.js @@ -523,14 +523,61 @@ function appendJobLog(message) { return; } - const time = new Date().toLocaleTimeString('ru-RU', { hour12: false }); + const parsed = parseServerLogLine(message); + if (isCollectLogNoise(parsed.message)) { + // Still count toward log length so syncServerLogs offset stays correct, + // but mark as hidden so renderCollectionJob skips it. + collectionJob.logs.push({ + id: ++collectionJobLogCounter, + time: parsed.time || new Date().toLocaleTimeString('ru-RU', { hour12: false }), + message: parsed.message, + hidden: true + }); + return; + } + collectionJob.logs.push({ id: ++collectionJobLogCounter, - time, - message + time: parsed.time || new Date().toLocaleTimeString('ru-RU', { hour12: false }), + message: humanizeCollectLogMessage(parsed.message) }); } +// Transform technical log messages into human-readable form for the UI. +// The original messages are preserved in collect.log / raw_export. +function humanizeCollectLogMessage(msg) { + // "Redfish snapshot: документов=520, ETA≈16s, корни=Chassis(294), Systems(114), последний=/redfish/v1/..." + // → "Snapshot: /Chassis/Self/PCIeDevices/00_34_04" + let m = msg.match(/snapshot:\s+документов=\d+[^,]*,.*последний=(\S+)/i); + if (m) { + const path = m[1].replace(/^\.\.\./, '').replace(/^\/redfish\/v1/, '') || m[1]; + return `Snapshot: ${path}`; + } + + // "Redfish snapshot: собрано N документов" + m = msg.match(/snapshot:\s+собрано\s+(\d+)\s+документов/i); + if (m) { + return `Snapshot: итого ${m[1]} документов`; + } + + // "Redfish: plan-B завершен за 30s (targets=18, recovered=0)" + m = msg.match(/plan-B завершен за ([^(]+)\(targets=(\d+),\s*recovered=(\d+)\)/i); + if (m) { + const recovered = parseInt(m[3], 10); + const suffix = recovered > 0 ? `, восстановлено ${m[3]}` : ''; + return `Plan-B: завершен за ${m[1].trim()}${suffix}`; + } + + // "Redfish: prefetch критичных endpoint (адаптивно 9/72)..." + m = msg.match(/prefetch критичных endpoint[^(]*\(([^)]+)\)/i); + if (m) { + return `Prefetch критичных endpoint (${m[1]})`; + } + + // Strip "Redfish: " / "Redfish snapshot: " prefix — redundant in context + return msg.replace(/^Redfish(?:\s+snapshot)?:\s+/i, ''); +} + function renderCollectionJob() { const jobStatusBlock = document.getElementById('api-job-status'); const jobIdValue = document.getElementById('job-id-value'); @@ -576,9 +623,11 @@ function renderCollectionJob() { renderJobActiveModules(activeModulesBlock, activeModulesList); renderJobDebugInfo(debugInfoBlock, debugSummary, phaseTelemetryNode); - logsList.innerHTML = [...collectionJob.logs].reverse().map((log) => ( - `