332 lines
13 KiB
JSON
332 lines
13 KiB
JSON
{
|
|
"name": "Homelab Log Analyzer",
|
|
"nodes": [
|
|
{
|
|
"parameters": {
|
|
"rule": {
|
|
"interval": [
|
|
{
|
|
"field": "hours",
|
|
"hoursInterval": 6
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"id": "schedule-trigger",
|
|
"name": "Every 6 Hours",
|
|
"type": "n8n-nodes-base.scheduleTrigger",
|
|
"typeVersion": 1.2,
|
|
"position": [
|
|
250,
|
|
400
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"command": "docker service logs --tail 100 --timestamps traefik_traefik 2>&1 || echo 'Service not found'"
|
|
},
|
|
"id": "logs-traefik",
|
|
"name": "Get Traefik Logs",
|
|
"type": "n8n-nodes-base.executeCommand",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
500,
|
|
200
|
|
],
|
|
"continueOnFail": true
|
|
},
|
|
{
|
|
"parameters": {
|
|
"command": "docker service logs --tail 100 --timestamps n8n_n8n 2>&1 || echo 'Service not found'"
|
|
},
|
|
"id": "logs-n8n",
|
|
"name": "Get n8n Logs",
|
|
"type": "n8n-nodes-base.executeCommand",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
500,
|
|
350
|
|
],
|
|
"continueOnFail": true
|
|
},
|
|
{
|
|
"parameters": {
|
|
"command": "docker service logs --tail 100 --timestamps ai_openwebui 2>&1 || echo 'Service not found'"
|
|
},
|
|
"id": "logs-openwebui",
|
|
"name": "Get OpenWebUI Logs",
|
|
"type": "n8n-nodes-base.executeCommand",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
500,
|
|
500
|
|
],
|
|
"continueOnFail": true
|
|
},
|
|
{
|
|
"parameters": {
|
|
"command": "docker service logs --tail 100 --timestamps infrastructure_komodo-core 2>&1 || echo 'Service not found'"
|
|
},
|
|
"id": "logs-komodo",
|
|
"name": "Get Komodo Logs",
|
|
"type": "n8n-nodes-base.executeCommand",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
500,
|
|
650
|
|
],
|
|
"continueOnFail": true
|
|
},
|
|
{
|
|
"parameters": {
|
|
"command": "docker service logs --tail 100 --timestamps monitoring_prometheus 2>&1 || echo 'Service not found'"
|
|
},
|
|
"id": "logs-prometheus",
|
|
"name": "Get Prometheus Logs",
|
|
"type": "n8n-nodes-base.executeCommand",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
500,
|
|
800
|
|
],
|
|
"continueOnFail": true
|
|
},
|
|
{
|
|
"parameters": {
|
|
"jsCode": "const items = $input.all();\n\nconst logAnalysis = {\n timestamp: new Date().toISOString(),\n services: [],\n errors: [],\n warnings: [],\n summary: {}\n};\n\nconst errorPatterns = [\n /ERROR/gi,\n /FATAL/gi,\n /CRITICAL/gi,\n /FAIL/gi,\n /panic:/gi,\n /exception/gi\n];\n\nconst warningPatterns = [\n /WARN/gi,\n /WARNING/gi,\n /deprecated/gi,\n /timeout/gi,\n /retry/gi\n];\n\nfor (const item of items) {\n const nodeName = item.json.node || 'unknown';\n const stdout = item.json.stdout || '';\n const lines = stdout.split('\\n').filter(l => l.trim());\n \n const serviceLog = {\n name: nodeName,\n totalLines: lines.length,\n errors: [],\n warnings: [],\n recentEntries: lines.slice(-10) // Last 10 lines\n };\n \n // Scan for errors and warnings\n lines.forEach(line => {\n const matchesError = errorPatterns.some(pattern => pattern.test(line));\n const matchesWarning = warningPatterns.some(pattern => pattern.test(line));\n \n if (matchesError) {\n const errorEntry = {\n service: nodeName,\n line: line,\n timestamp: line.match(/^\\d{4}-\\d{2}-\\d{2}T[\\d:]+\\.\\d+Z/) ? line.split(' ')[0] : null\n };\n serviceLog.errors.push(errorEntry);\n logAnalysis.errors.push(errorEntry);\n } else if (matchesWarning) {\n const warningEntry = {\n service: nodeName,\n line: line,\n timestamp: line.match(/^\\d{4}-\\d{2}-\\d{2}T[\\d:]+\\.\\d+Z/) ? line.split(' ')[0] : null\n };\n serviceLog.warnings.push(warningEntry);\n logAnalysis.warnings.push(warningEntry);\n }\n });\n \n logAnalysis.services.push(serviceLog);\n}\n\n// Generate summary\nlogAnalysis.summary = {\n totalServices: logAnalysis.services.length,\n totalErrors: logAnalysis.errors.length,\n totalWarnings: logAnalysis.warnings.length,\n servicesWithErrors: logAnalysis.services.filter(s => s.errors.length > 0).map(s => s.name),\n servicesWithWarnings: logAnalysis.services.filter(s => s.warnings.length > 0).map(s => s.name)\n};\n\nreturn [{ json: logAnalysis }];"
|
|
},
|
|
"id": "parse-logs",
|
|
"name": "Parse and Analyze Logs",
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
750,
|
|
500
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "POST",
|
|
"url": "=http://lm-studio:1234/v1/chat/completions",
|
|
"sendBody": true,
|
|
"bodyParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "model",
|
|
"value": "=qwen2.5-coder-7b-instruct"
|
|
},
|
|
{
|
|
"name": "messages",
|
|
"value": "={{ [{\"role\":\"system\",\"content\":\"You are a Docker/Kubernetes expert and log analyzer. Analyze these Docker service logs and identify: 1) Critical issues requiring immediate attention 2) Performance concerns 3) Configuration problems 4) Recommended actions. Respond in JSON format with: critical_issues (array), performance_concerns (array), config_issues (array), recommendations (array).\"}, {\"role\":\"user\",\"content\":\"Analyze these homelab service logs:\\n\\nSummary: \" + JSON.stringify($json.summary, null, 2) + \"\\n\\nErrors Found: \" + JSON.stringify($json.errors.slice(0, 20), null, 2) + \"\\n\\nWarnings Found: \" + JSON.stringify($json.warnings.slice(0, 20), null, 2)}] }}"
|
|
},
|
|
{
|
|
"name": "temperature",
|
|
"value": "=0.2"
|
|
},
|
|
{
|
|
"name": "max_tokens",
|
|
"value": "=1500"
|
|
}
|
|
]
|
|
},
|
|
"options": {
|
|
"timeout": 30000
|
|
}
|
|
},
|
|
"id": "ai-log-analysis",
|
|
"name": "AI Log Analysis",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
1000,
|
|
500
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"jsCode": "const logData = $('Parse and Analyze Logs').item.json;\nconst aiResponse = $json.choices[0].message.content;\n\nlet aiAnalysis;\ntry {\n // Extract JSON from response (AI might wrap it in markdown)\n const jsonMatch = aiResponse.match(/\\{[\\s\\S]*\\}/);\n aiAnalysis = jsonMatch ? JSON.parse(jsonMatch[0]) : { raw: aiResponse };\n} catch (e) {\n aiAnalysis = { raw: aiResponse };\n}\n\nconst report = {\n generated_at: new Date().toISOString(),\n period: '6 hours',\n summary: logData.summary,\n top_errors: logData.errors.slice(0, 10),\n top_warnings: logData.warnings.slice(0, 10),\n ai_analysis: aiAnalysis,\n action_required: logData.summary.totalErrors > 10 || (aiAnalysis.critical_issues && aiAnalysis.critical_issues.length > 0)\n};\n\nreturn [{ json: report }];"
|
|
},
|
|
"id": "build-log-report",
|
|
"name": "Build Log Report",
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
1250,
|
|
500
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"conditions": {
|
|
"options": {
|
|
"leftValue": "",
|
|
"caseSensitive": true,
|
|
"typeValidation": "strict"
|
|
},
|
|
"combinator": "or",
|
|
"conditions": [
|
|
{
|
|
"id": "has-action-required",
|
|
"leftValue": "={{ $json.action_required }}",
|
|
"rightValue": true,
|
|
"operator": {
|
|
"type": "boolean",
|
|
"operation": "true"
|
|
}
|
|
},
|
|
{
|
|
"id": "many-errors",
|
|
"leftValue": "={{ $json.summary.totalErrors }}",
|
|
"rightValue": 5,
|
|
"operator": {
|
|
"type": "number",
|
|
"operation": "gt"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"id": "should-alert-logs",
|
|
"name": "Should Alert?",
|
|
"type": "n8n-nodes-base.if",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
1500,
|
|
500
|
|
]
|
|
}
|
|
],
|
|
"pinData": {},
|
|
"connections": {
|
|
"Every 6 Hours": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Get Traefik Logs",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Get n8n Logs",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Get OpenWebUI Logs",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Get Komodo Logs",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Get Prometheus Logs",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Get Traefik Logs": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Parse and Analyze Logs",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Get n8n Logs": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Parse and Analyze Logs",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Get OpenWebUI Logs": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Parse and Analyze Logs",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Get Komodo Logs": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Parse and Analyze Logs",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Get Prometheus Logs": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Parse and Analyze Logs",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Parse and Analyze Logs": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "AI Log Analysis",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"AI Log Analysis": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Build Log Report",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Build Log Report": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Should Alert?",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
}
|
|
},
|
|
"active": false,
|
|
"settings": {
|
|
"executionOrder": "v1"
|
|
},
|
|
"versionId": "1",
|
|
"meta": {
|
|
"templateCredsSetupCompleted": true,
|
|
"instanceId": "homelab"
|
|
},
|
|
"id": "homelab-log-analyzer",
|
|
"tags": []
|
|
} |