diff --git a/diagnostic/index.html b/diagnostic/index.html
index fb7234f..233f393 100644
--- a/diagnostic/index.html
+++ b/diagnostic/index.html
@@ -127,11 +127,15 @@
+
@@ -151,14 +156,16 @@
const btnScroll = document.getElementById('btn-scroll');
let ws;
let activeTab = 'all';
- const autoScroll = { all: true, gateway: true, rvs: true, proxy: true, server: true };
- const logCounts = { all: 0, gateway: 0, rvs: 0, proxy: 0, server: 0 };
+ const DOCKER_TABS = ['gateway', 'proxy', 'bridge'];
+ const autoScroll = { all: true, gateway: true, rvs: true, proxy: true, bridge: true, server: true };
+ const logCounts = { all: 0, gateway: 0, rvs: 0, proxy: 0, bridge: 0, server: 0 };
const logBoxes = {
all: document.getElementById('log-all'),
gateway: document.getElementById('log-gateway'),
rvs: document.getElementById('log-rvs'),
proxy: document.getElementById('log-proxy'),
+ bridge: document.getElementById('log-bridge'),
server: document.getElementById('log-server'),
};
@@ -186,6 +193,8 @@
activeTab = tab;
document.querySelectorAll('.tab-btn').forEach(b => b.classList.toggle('active', b.dataset.tab === tab));
Object.entries(logBoxes).forEach(([t, box]) => box.classList.toggle('hidden', t !== tab));
+ // Docker Logs Button nur bei Tabs mit Containern
+ document.getElementById('btn-docker-logs').style.display = DOCKER_TABS.includes(tab) ? 'inline' : 'none';
// Pause-Hinweis aktualisieren
const box = logBoxes[tab];
const atBottom = box.scrollHeight - box.scrollTop - box.clientHeight < 30;
@@ -209,6 +218,7 @@
if (source === 'gateway') return 'gateway';
if (source === 'rvs') return 'rvs';
if (source === 'proxy') return 'proxy';
+ if (source === 'bridge') return 'bridge';
if (source === 'server' || source === 'browser') return 'server';
return null;
}
@@ -267,6 +277,10 @@
}
return;
}
+ if (msg.type === 'docker_logs') {
+ showDockerLogs(msg);
+ return;
+ }
if (msg.type === 'response') { return; }
};
}
@@ -295,6 +309,11 @@
send({ action: 'test_proxy', text: 'Antworte mit genau einem Wort: Ping' });
}
+ function loadDockerLogs() {
+ if (!DOCKER_TABS.includes(activeTab)) return;
+ send({ action: 'docker_logs', tab: activeTab, tail: 200 });
+ }
+
function updateState(state) {
// Gateway
const gw = state.gateway || {};
@@ -350,6 +369,40 @@
chatBox.scrollTop = chatBox.scrollHeight;
}
+ function showDockerLogs(msg) {
+ const tab = msg.tab;
+ const box = logBoxes[tab];
+ if (!box) return;
+
+ if (msg.error) {
+ appendToLog(tab, 'error', `Docker Logs Fehler: ${msg.error}`);
+ return;
+ }
+
+ // Bestehende Eintraege leeren und Docker-Logs einfuegen
+ box.innerHTML = '';
+ const header = document.createElement('div');
+ header.className = 'log-entry info';
+ header.textContent = `── Docker Logs: ${msg.container} (letzte ${msg.lines.length} Zeilen) ──`;
+ box.appendChild(header);
+
+ for (const line of msg.lines) {
+ const el = document.createElement('div');
+ el.className = 'log-entry ' + (line.match(/\b(error|Error|ERROR)\b/) ? 'error' :
+ line.match(/\b(warn|Warning|WARN)\b/) ? 'warn' : 'info');
+ el.textContent = line;
+ box.appendChild(el);
+ }
+
+ // Zähler aktualisieren
+ logCounts[tab] = msg.lines.length;
+ const countEl = document.getElementById(`count-${tab}`);
+ if (countEl) countEl.textContent = logCounts[tab];
+
+ box.scrollTop = box.scrollHeight;
+ autoScroll[tab] = true;
+ }
+
function escapeHtml(str) {
return str.replace(/&/g,'&').replace(//g,'>');
}
diff --git a/diagnostic/server.js b/diagnostic/server.js
index c3d3ed2..84239d2 100644
--- a/diagnostic/server.js
+++ b/diagnostic/server.js
@@ -409,6 +409,66 @@ async function testProxy(prompt) {
}
}
+// ── Docker Container Logs ────────────────────────────────
+
+const CONTAINER_MAP = {
+ gateway: "aria-core",
+ proxy: "aria-proxy",
+ bridge: "aria-bridge",
+};
+
+function fetchDockerLogs(tab, tail) {
+ const containerName = CONTAINER_MAP[tab];
+ if (!containerName) return;
+
+ const lines = parseInt(tail, 10) || 100;
+ const dockerPath = `/containers/${containerName}/logs?stdout=true&stderr=true&tail=${lines}×tamps=true`;
+
+ return new Promise((resolve, reject) => {
+ const req = http.request(
+ { socketPath: "/var/run/docker.sock", path: dockerPath, method: "GET" },
+ (res) => {
+ const chunks = [];
+ res.on("data", (chunk) => chunks.push(chunk));
+ res.on("end", () => {
+ // Docker log stream hat 8-byte Header pro Frame (stream type + size)
+ const raw = Buffer.concat(chunks);
+ const logLines = [];
+ let offset = 0;
+ while (offset < raw.length) {
+ if (offset + 8 > raw.length) break;
+ const size = raw.readUInt32BE(offset + 4);
+ if (offset + 8 + size > raw.length) break;
+ const line = raw.slice(offset + 8, offset + 8 + size).toString("utf-8").trimEnd();
+ if (line) logLines.push(line);
+ offset += 8 + size;
+ }
+ resolve(logLines);
+ });
+ }
+ );
+ req.on("error", (err) => reject(err));
+ req.end();
+ });
+}
+
+async function handleDockerLogs(ws, tab, tail) {
+ const containerName = CONTAINER_MAP[tab];
+ if (!containerName) {
+ ws.send(JSON.stringify({ type: "docker_logs", tab, error: `Unbekannter Tab: ${tab}` }));
+ return;
+ }
+
+ try {
+ log("info", "server", `Lade Docker-Logs: ${containerName} (tail ${tail || 100})`);
+ const lines = await fetchDockerLogs(tab, tail);
+ ws.send(JSON.stringify({ type: "docker_logs", tab, container: containerName, lines }));
+ } catch (err) {
+ log("error", "server", `Docker-Logs Fehler (${containerName}): ${err.message}`);
+ ws.send(JSON.stringify({ type: "docker_logs", tab, error: err.message }));
+ }
+}
+
// ── Hilfsfunktionen ─────────────────────────────────────
function waitForMessage(ws, timeoutMs) {
@@ -462,6 +522,8 @@ wss.on("connection", (ws) => {
connectRVS();
} else if (msg.action === "test_proxy") {
testProxy(msg.text);
+ } else if (msg.action === "docker_logs") {
+ handleDockerLogs(ws, msg.tab, msg.tail);
}
} catch {}
});
diff --git a/docker-compose.yml b/docker-compose.yml
index b8574fb..f660582 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -74,6 +74,8 @@ services:
depends_on:
- aria
network_mode: "service:aria" # Teilt Netzwerk mit aria-core → localhost:18789
+ volumes:
+ - /var/run/docker.sock:/var/run/docker.sock:ro
environment:
- ARIA_AUTH_TOKEN=${ARIA_AUTH_TOKEN:-}
- PROXY_URL=http://proxy:3456