Upgrade logs

This commit is contained in:
Raven Scott
2026-05-28 12:12:24 -04:00
parent 6ee20a3f68
commit ca324ec4a6
15 changed files with 610 additions and 105 deletions
@@ -0,0 +1,61 @@
/**
* Per-channel log tail subscriptions over admin WebSocket.
*/
const { getLogTail, listLogChannels } = require('../../infrastructure/log-files');
/** @type {Map<import('ws'), string>} */
const logSubscribers = new Map();
function handleLogWsMessage(ws, data) {
if (data.type === 'subscribe-log') {
const channel = data.channel || 'core';
if (!listLogChannels().some((c) => c.id === channel)) {
return false;
}
logSubscribers.set(ws, channel);
if (ws.readyState === 1) {
const lines = getLogTail(channel, data.lines || 500);
ws.send(JSON.stringify({
type: 'log-snapshot',
channel,
lines
}));
}
return true;
}
if (data.type === 'unsubscribe-log') {
logSubscribers.delete(ws);
return true;
}
return false;
}
function onLogWsClose(ws) {
logSubscribers.delete(ws);
}
function notifyLogSubscribers(channelId, level, line) {
const payload = JSON.stringify({
type: 'file-log',
channel: channelId,
level,
message: line
});
for (const [ws, subscribed] of logSubscribers.entries()) {
if (subscribed !== channelId) continue;
if (ws.readyState === 1) {
ws.send(payload);
}
}
}
function closeLogWebSocketState() {
logSubscribers.clear();
}
module.exports = {
handleLogWsMessage,
onLogWsClose,
notifyLogSubscribers,
closeLogWebSocketState
};
+3 -1
View File
@@ -15,6 +15,7 @@ const { handleBackupsRoutes } = require('./backups');
const { handleDiagnosticsRoutes } = require('./diagnostics');
const { handleConsensusRoutes } = require('./consensus');
const { handlePluginsRoutes } = require('./plugins');
const { handleLogsRoutes } = require('./logs');
async function handleAdminRequest(req, res) {
const url = new URL(req.url, `https://${req.headers.host}`);
@@ -52,7 +53,8 @@ async function handleAdminRequest(req, res) {
if (await handleDiagnosticsRoutes(req, res)) return;
if (await handleConsensusRoutes(req, res)) return;
if (await handlePluginsRoutes(req, res)) return;
if (await handleLogsRoutes(req, res)) return;
// No route matched
res.writeHead(404);
res.end('Not Found');
@@ -0,0 +1,33 @@
const { listLogChannels, getLogTail } = require('../../../infrastructure/log-files');
async function handleLogsRoutes(req, res) {
const urlPath = req.urlPath;
const method = req.method;
if (method === 'GET' && urlPath === '/api/logs') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ channels: listLogChannels() }));
return true;
}
const match = urlPath.match(/^\/api\/logs\/([a-z]+)$/);
if (method === 'GET' && match) {
const channelId = match[1];
const channels = listLogChannels();
if (!channels.some((c) => c.id === channelId)) {
res.writeHead(404, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: 'Unknown log channel' }));
return true;
}
const url = new URL(req.url, `https://${req.headers.host}`);
const lines = Math.min(parseInt(url.searchParams.get('lines') || '500', 10), 5000);
const tail = getLogTail(channelId, lines);
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ channel: channelId, lines: tail }));
return true;
}
return false;
}
module.exports = { handleLogsRoutes };
+10
View File
@@ -11,6 +11,11 @@ const {
notifyStatsSubscribers,
closeStatsWebSocketState
} = require('./stats-websocket');
const {
handleLogWsMessage,
onLogWsClose,
closeLogWebSocketState
} = require('./log-websocket');
const adminWss = new WebSocket.Server({ noServer: true });
const adminClients = new Set();
@@ -119,6 +124,8 @@ adminWss.on('connection', (ws) => {
});
} else if (handleStatsWsMessage(ws, data)) {
// subscribe-stats / unsubscribe-stats / request-stats-snapshot
} else if (handleLogWsMessage(ws, data)) {
// subscribe-log / unsubscribe-log
}
} catch (err) {
logError('Admin', `Error handling WebSocket message: ${err.message}`);
@@ -128,6 +135,7 @@ adminWss.on('connection', (ws) => {
// Handle close event
ws.on('close', () => {
onStatsWsClose(ws);
onLogWsClose(ws);
adminClients.delete(ws);
logDebug('Admin', 'WebSocket client disconnected');
});
@@ -136,6 +144,7 @@ adminWss.on('connection', (ws) => {
ws.on('error', (err) => {
logError('Admin', `WebSocket error: ${err.message}`);
onStatsWsClose(ws);
onLogWsClose(ws);
adminClients.delete(ws);
try {
if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING) {
@@ -186,6 +195,7 @@ function closeAllWebSockets() {
}
adminClients.clear();
closeStatsWebSocketState();
closeLogWebSocketState();
// Stop health broadcasts
stopHealthBroadcasts();