diff options
| author | Agando <roduccomm@gmail.com> | 2026-06-04 06:01:04 +0200 |
|---|---|---|
| committer | Agando <roduccomm@gmail.com> | 2026-06-04 06:01:04 +0200 |
| commit | a5023e61be61f2f2287342039addab6bb28ad2fd (patch) | |
| tree | 9b1b3c166869cd6fee91bffe1f4134513005b8b1 /modules/core/module-servermon.js | |
| parent | 301f75ab03302a05b3c35950a3b0ab49f9f69ed6 (diff) | |
auto: 2026-06-04_06:00 changes
Diffstat (limited to 'modules/core/module-servermon.js')
| -rw-r--r-- | modules/core/module-servermon.js | 172 |
1 files changed, 140 insertions, 32 deletions
diff --git a/modules/core/module-servermon.js b/modules/core/module-servermon.js index 23407db..293e9af 100644 --- a/modules/core/module-servermon.js +++ b/modules/core/module-servermon.js @@ -1,35 +1,143 @@ -// Extracted from newOS4 index.html — ServerMonitorModule - class ServerMonitorModule { - constructor() { - this.commands = {}; this.terminal = null; - this.servers = this.loadServers(); this.monitorInterval = null; - } - getHelpInfo() { - return { - 'server': 'Add a server to monitor: server <name> <url>', - 'servers': 'List all monitored servers', - 'server-check': 'Check a server status: server-check <name-or-index>', - 'server-remove': 'Remove a server: server-remove <name-or-index>', - 'monitor': 'Toggle auto-monitoring (checks every 60s)' - }; - } - loadServers() { - try { - const saved = localStorage.getItem('webx11_servers'); - return saved ? JSON.parse(saved) : []; - } catch (e) { return []; } - } - saveServers() { - localStorage.setItem('webx11_servers', JSON.stringify(this.servers)); - } - registerCommands() { - this.commands['server'] = (args) => this.addServer(args); - this.commands['servers'] = () => this.listServers(); - this.commands['server-check'] = (args) => this.checkServer(args); - this.commands['server-remove'] = (args) => this.removeServer(args); - this.commands['monitor'] = (args) => this.toggleMonitor(args); - } - addServer(args) { +// module-servermon.js — Server monitoring + self-optimization telemetry +// Commands: server, servers, server-check, server-remove, monitor, system-health +class ServerMonitorModule { + constructor() { + this.commands = {}; this.terminal = null; + this.servers = this.loadServers(); this.monitorInterval = null; + this._latencyLog = []; + this._maxLatencyEntries = 200; + } + getHelpInfo() { + return { + 'server': 'server <name> <url> — Add a server to monitor', + 'servers': 'servers — List all monitored servers', + 'server-check': 'server-check <name-or-index> — Check a server status', + 'server-remove': 'server-remove <name-or-index> — Remove a server', + 'monitor': 'monitor — Toggle auto-monitoring (checks every 60s)', + 'system-health': 'system-health — Show tool latency, module load times, VFS size, and error rates' + }; + } + registerCommands() { + this.commands['server'] = (args) => this.addServer(args); + this.commands['servers'] = () => this.listServers(); + this.commands['server-check'] = (args) => this.checkServer(args); + this.commands['server-remove'] = (args) => this.removeServer(args); + this.commands['monitor'] = (args) => this.toggleMonitor(args); + this.commands['system-health'] = () => this.showSystemHealth(); + } + logToolCall(name, durationMs, error) { + this._latencyLog.push({ + name, + duration: durationMs, + error: !!error, + time: Date.now() + }); + if (this._latencyLog.length > this._maxLatencyEntries) { + this._latencyLog = this._latencyLog.slice(-this._maxLatencyEntries); + } + // Persist every 20 calls + if (this._latencyLog.length % 20 === 0) { + this._persistLatency(); + } + } + _persistLatency() { + try { + this.terminal.fs.fsWriteJSON('/system/metrics/tool-latency.json', this._latencyLog.slice(-100)); + } catch (e) {} + } + _loadLatency() { + try { + const data = this.terminal.fs.fsReadJSON('/system/metrics/tool-latency.json'); + if (data) this._latencyLog = data; + } catch (e) {} + } + showSystemHealth() { + this._loadLatency(); + const fs = this.terminal.fs; + + // Tool latency stats + const toolStats = {}; + for (const entry of this._latencyLog) { + if (!toolStats[entry.name]) toolStats[entry.name] = { calls: 0, totalMs: 0, errors: 0, maxMs: 0 }; + toolStats[entry.name].calls++; + toolStats[entry.name].totalMs += entry.duration; + toolStats[entry.name].errors += entry.error ? 1 : 0; + toolStats[entry.name].maxMs = Math.max(toolStats[entry.name].maxMs, entry.duration); + } + + this.terminal.print('📊 System Health', 'header'); + + // Tool latency table (sorted by avg desc) + this.terminal.print('── Tool Latency ──', 'info'); + const sorted = Object.entries(toolStats) + .map(([name, s]) => ({ name, avg: (s.totalMs / s.calls).toFixed(0), ...s })) + .sort((a, b) => b.avg - a.avg); + for (const t of sorted.slice(0, 10)) { + const avgMs = t.avg.padStart(5); + const maxMs = String(t.maxMs).padStart(5); + const err = t.errors > 0 ? ` ⚠️${t.errors}` : ''; + this.terminal.print(` ${avgMs}ms avg / ${maxMs}ms max — ${t.name} (${t.calls} calls)${err}`, t.errors > 0 ? 'warning' : ''); + } + if (sorted.length > 10) this.terminal.print(` ... and ${sorted.length - 10} more tools`, 'info'); + + // VFS stats + this.terminal.print('── VFS Stats ──', 'info'); + try { + const totalSize = this._vfsSize(fs.root); + const fileCount = this._vfsCount(fs.root, 'file'); + const dirCount = this._vfsCount(fs.root, 'dir'); + this.terminal.print(` ${fileCount} files, ${dirCount} dirs, ${(totalSize / 1024).toFixed(0)} KB total`, ''); + } catch (e) { this.terminal.print(' VFS stats unavailable', 'warning'); } + + // Module stats + this.terminal.print('── Module Stats ──', 'info'); + const mm = this.terminal.moduleManager; + const loaded = Object.keys(mm.modules).length; + const reg = (mm.moduleRegistry || []).length; + this.terminal.print(` ${loaded} modules loaded, ${reg} in registry`, ''); + + // Memory + this.terminal.print('── Memory ──', 'info'); + if (performance.memory) { + const heap = (performance.memory.usedJSHeapSize / 1048576).toFixed(1); + const total = (performance.memory.jsHeapSizeLimit / 1048576).toFixed(0); + this.terminal.print(` ${heap} MB used / ${total} MB limit`, heap > 100 ? 'warning' : ''); + } else { + this.terminal.print(' Memory info not available (non-Chrome browser)', ''); + } + + // Total tool call count + const totalCalls = this._latencyLog.length; + const totalErrors = this._latencyLog.filter(e => e.error).length; + this.terminal.print(` ${totalCalls} tool calls logged, ${totalErrors} errors (${totalCalls > 0 ? (totalErrors / totalCalls * 100).toFixed(1) : 0}% error rate)`, totalErrors > 0 ? 'warning' : ''); + } + _vfsSize(node) { + if (!node) return 0; + if (node.type === 'file') return (node.content || '').length; + let s = 0; + for (const k in (node.content || {})) s += this._vfsSize(node.content[k]); + return s; + } + _vfsCount(node, type) { + if (!node) return 0; + let c = 0; + for (const k in (node.content || {})) { + const child = node.content[k]; + if (child.type === type) c++; + c += this._vfsCount(child, type); + } + return c; + } + loadServers() { + try { + const saved = localStorage.getItem('webx11_servers'); + return saved ? JSON.parse(saved) : []; + } catch (e) { return []; } + } + saveServers() { + localStorage.setItem('webx11_servers', JSON.stringify(this.servers)); + } + addServer(args) { if (args.length < 2) { this.terminal.print("Usage: server <name> <url>", "warning"); return; } |