fix(analyze_logs): scan-all-Modus funktionierte nicht

docker logs ohne Container-Argument schlägt fehl → 0 Treffer.
Jetzt: Loop über alle laufenden Container (docker ps), pro Match
Container-Name in sample_matches + containers_with_matches im
Output. Tool-Beschreibung angepasst.
This commit is contained in:
Mikei386
2026-08-18 13:44:01 +02:00
parent c8c767d45b
commit c4c9752521
2 changed files with 30 additions and 13 deletions
+24 -7
View File
@@ -325,23 +325,39 @@ export async function analyzeContainerLogs(
const patterns = severityLevels[severity] ?? severityLevels["error"]; const patterns = severityLevels[severity] ?? severityLevels["error"];
const regex = new RegExp(`(${patterns.join("|")})`, "i"); const regex = new RegExp(`(${patterns.join("|")})`, "i");
let logCmd = `logs --timestamps --since ${since} --tail ${scanTail}`; // Ziel-Container: einzelner Container oder alle laufenden
if (container) logCmd += ` ${container}`; let targets: string[];
const raw = await dockerExec(logCmd, 120); if (container) {
const lines = raw.split("\n"); targets = [container];
} else {
const psRaw = await dockerExec("ps --format '{{.Names}}'", 30);
targets = psRaw
.split("\n")
.map((l) => l.trim())
.filter((l) => l.length > 0);
}
const matches: { pattern: string; line: string }[] = []; const matches: { pattern: string; line: string; container: string }[] = [];
const counts: Record<string, number> = {}; const counts: Record<string, number> = {};
for (const line of lines) { const containersWithMatches: Record<string, number> = {};
for (const name of targets) {
const logCmd = `logs --timestamps --since ${since} --tail ${scanTail} ${name}`;
const raw = await dockerExec(logCmd, 120);
let containerMatches = 0;
for (const line of raw.split("\n")) {
const m = line.match(regex); const m = line.match(regex);
if (m) { if (m) {
const key = m[1].toLowerCase(); const key = m[1].toLowerCase();
counts[key] = (counts[key] ?? 0) + 1; counts[key] = (counts[key] ?? 0) + 1;
containerMatches++;
if (matches.length < maxResults) { if (matches.length < maxResults) {
matches.push({ pattern: m[1], line: line.trim().slice(0, 300) }); matches.push({ pattern: m[1], line: line.trim().slice(0, 300), container: name });
} }
} }
} }
if (containerMatches > 0) containersWithMatches[name] = containerMatches;
}
return JSON.stringify({ return JSON.stringify({
schema_version: "1.0", schema_version: "1.0",
@@ -351,6 +367,7 @@ export async function analyzeContainerLogs(
scan_tail: scanTail, scan_tail: scanTail,
total_matches: Object.values(counts).reduce((a, b) => a + b, 0), total_matches: Object.values(counts).reduce((a, b) => a + b, 0),
pattern_counts: counts, pattern_counts: counts,
containers_with_matches: containersWithMatches,
sample_matches: matches, sample_matches: matches,
}); });
} }
+1 -1
View File
@@ -85,7 +85,7 @@ export const TOOLS: ToolDef[] = [
enum: ["error", "warn", "info"], enum: ["error", "warn", "info"],
description: "Log severity to scan for", description: "Log severity to scan for",
}, },
container: str("Container name (optional, scans all if omitted)"), container: str("Container name (optional, scans all running containers if omitted)"),
since: str("Time filter (default 24h)"), since: str("Time filter (default 24h)"),
scan_tail: int("Max lines to scan (default 1000)"), scan_tail: int("Max lines to scan (default 1000)"),
max_results: int("Max sample matches (default 50)"), max_results: int("Max sample matches (default 50)"),