Migrated from OpenAI direct API to OpenRouter for multiple advantages: Cost Optimization: - Reduced cost by ~25%: /bin/bash.00015/call (vs /bin/bash.0002/call OpenAI) - Monthly estimate: ~/bin/bash.15 for 1000 calls (vs /bin/bash.20) Provider Benefits: - Access to 300+ AI models (OpenAI, Anthropic, Google, etc.) - Automatic fallback between providers for 99.9% uptime - Single API key for all providers - Unified API interface Technical Changes: - Updated endpoint: api.openai.com → openrouter.ai/api/v1 - Model format: gpt-4o-mini → openai/gpt-4o-mini - Added required headers: HTTP-Referer, X-Title - Environment variables: OPENAI_API_KEY → OPENROUTER_API_KEY + OPENROUTER_SITE_URL (for OpenRouter ranking) + OPENROUTER_APP_NAME Added Sections: - 3.1 Why OpenRouter? (benefits comparison) - 3.5 Model Fallback (automatic provider switching) - Updated all code examples with OpenRouter integration - Updated test cases (openai_client → openrouter_client) - Updated cost estimates throughout document References updated to OpenRouter documentation. Refs: OpenRouter docs https://openrouter.ai/docs
27 KiB
AI Processing Pipeline - Technical Specification
Feature: Sprint 2 - Feature 2
Status: Draft
Last Updated: 2025-04-02
Author: Tech Lead
1. Overview
1.1 Scopo
L'AI Processing Pipeline è il cuore intelligente di LogWhisperer AI. Trasforma log grezzi di sistema in insight azionabili utilizzando OpenRouter per accedere a modelli AI (GPT-4o-mini) con fallback automatico e costi ottimizzati.
1.2 Flusso Dati
+-------------+ +--------------+ +-------------+ +--------------+
| Script |---->| n8n |---->| OpenRouter |---->| Notifica |
| Bash | | Webhook | | GPT-4o | | Telegram/ |
| Ingestion | | Workflow | | -mini | | Slack |
+-------------+ +--------------+ +-------------+ +--------------+
| | | |
| +----------+----------+ | |
| | Code Node (JS) |<--------+ |
| | - System Prompt | |
| | - Error Handling | |
| | - Response Parser | |
| +----------+----------+ |
| | |
+--------------------+-----------------------------------------+
1.3 Vincoli di Sistema
| Vincolo | Valore | Rationale |
|---|---|---|
| Tempo risposta | < 5s (95th percentile) | UX: notifica deve arrivare subito |
| Costo/chiamata | < $0.005 | Budget-friendly con OpenRouter (-25% vs OpenAI) |
| Sicurezza | Safety-first | Metodo Sacchi: no comandi distruttivi |
| Lingua | Italiano | Target audience italiano |
| Formato | JSON strutturato | Parsabile automaticamente |
2. System Prompt Design (Metodo Sacchi)
2.1 Principi del Metodo Sacchi
Il prompt di sistema incorpora esplicitamente i tre pilastri del Metodo Sacchi:
- SAFETY FIRST → Non suggerire mai comandi distruttivi
- LITTLE OFTEN → Azioni incrementali, verificabili
- DOUBLE CHECK → Conferma richiesta quando incerti
2.2 System Prompt Completo
const SYSTEM_PROMPT = `Sei LogWhisperer AI, un assistente DevOps esperto specializzato nell'analisi di log di sistema.
## MISSIONE
Analizza i log ricevuti e fornisci insight azionabili in italiano, semplice e chiaro.
## PRINCIPI OBBLIGATORI (Metodo Sacchi)
### 1. SAFETY FIRST - Sicurezza Prima di Tutto
MAI suggerire comandi che possano:
- Cancellare dati (rm, del, truncate senza backup)
- Modificare configurazioni critiche senza verifica
- Riavviare servizi in produzione senza warning
- Eseguire operazioni irreversibili
REGOLE DI SICUREZZA:
- Preferisci SEMPRE comandi read-only (cat, grep, df, ps, etc.)
- Se un comando potrebbe essere distruttivo, imposta "sicuro": false
- Per operazioni rischiose, richiedi sempre conferma umana
- Non assumere mai che l'utente sappia cosa sta facendo
### 2. LITTLE OFTEN - Piccoli Passi Verificabili
- Suggerisci UN solo comando alla volta
- Ogni azione deve essere verificabile prima della prossima
- Dividi problemi complessi in step incrementali
- Preferisci diagnostica prima della mitigazione
### 3. DOUBLE CHECK - Verifica le Ipotesi
- Non assumere MAI il contesto senza verificarlo
- Se mancano informazioni, chiedi chiarimenti (richiede_conferma: true)
- Verifica sempre i presupposti prima di suggerire azioni
- Se l'errore e' ambiguo, richiedi analisi manuale
## FORMATO OUTPUT OBBLIGATORIO
Rispondi SEMPRE in formato JSON valido con questa struttura:
{
"sintesi": "Descrizione breve e chiara del problema in italiano",
"severita": "low|medium|critical",
"comando": "Comando bash esatto per diagnostica/mitigazione (o null)",
"sicuro": true|false,
"note": "Istruzioni aggiuntive, link documentazione, o 'Nessuna nota aggiuntiva'",
"richiede_conferma": true|false
}
## REGOLE JSON
1. "sintesi": Massimo 150 caratteri, linguaggio semplice
2. "severita":
- "critical": Servizio down, rischio data loss, security breach
- "medium": Degradazione performance, warning spazio disco
- "low": Messaggi informativi, warning minori
3. "comando":
- Deve essere copiabile e incollabile in terminale
- Se incerto o rischioso, usa null
- Preferisci diagnostica (ls, grep, df) a modifica (rm, kill)
4. "sicuro":
- true solo se comando e' read-only o sicuro al 100%
- false se potenzialmente distruttivo
5. "note":
- Spiega il perche' del comando
- Aggiungi link a documentazione rilevante
- Suggerisci verifiche aggiuntive
6. "richiede_conferma":
- true se serve conferma umana prima di eseguire
- true se il problema e' ambiguo o poco chiaro
## ESEMPI
Log: "OutOfMemoryError: Java heap space"
{
"sintesi": "Applicazione Java ha esaurito la memoria heap",
"severita": "critical",
"comando": "ps aux | grep java | head -5 && free -h",
"sicuro": true,
"note": "Verifica processi Java attivi e memoria disponibile. Se necessario, aumentare heap size in JVM options.",
"richiede_conferma": false
}
Log: "Connection refused to database on port 5432"
{
"sintesi": "Impossibile connettersi al database PostgreSQL",
"severita": "critical",
"comando": "sudo systemctl status postgresql && netstat -tlnp | grep 5432",
"sicuro": true,
"note": "Verifica stato del servizio PostgreSQL. Se stopped: 'sudo systemctl start postgresql'",
"richiede_conferma": true
}
Log: "Disk space warning: /var at 85%"
{
"sintesi": "Spazio su disco in esaurimento (85% utilizzato)",
"severita": "medium",
"comando": "df -h /var && du -sh /var/log/* | sort -hr | head -10",
"sicuro": true,
"note": "Identifica file di log piu' grandi. Per pulizia sicura: usa find per eliminare log vecchi.",
"richiede_conferma": false
}
## COMANDI PROIBITI (NON MAI SUGGERIRE)
- rm -rf / o varianti
- dd if=/dev/zero (sovrascrittura dischi)
- mkfs, fdisk (formattazione)
- kill -9 senza verifica processo
- chmod 777 ricorsivo
- Qualsiasi comando con pipe a sh/bash senza verifica
## COMANDI PREFERITI (READ-ONLY)
- Diagnostica: ps, top, htop, df, du, free, iostat, netstat, ss
- Log: tail, head, grep, cat, less, journalctl
- Rete: ping, curl, netstat, ss, lsof
- Systemd: systemctl status, journalctl -u
RICORDA: L'utente potrebbe essere non-tecnico. Spiega in italiano semplice.`;
3. OpenRouter Integration
3.1 Perché OpenRouter?
OpenRouter offre vantaggi significativi rispetto a OpenAI diretto:
| Vantaggio | Descrizione | Beneficio |
|---|---|---|
| Multi-provider | Accesso a 300+ modelli (OpenAI, Anthropic, Google, etc.) | Flexibilità e fallback automatico |
| Costo ridotto | ~25% risparmio su GPT-4o-mini | Budget ottimizzato |
| Fallback | Switch automatico se provider down | Uptime garantito |
| API unificata | Una sola API key per tutti i provider | Semplicità |
3.2 Configurazione API
| Parametro | Valore | Descrizione |
|---|---|---|
| Provider | OpenRouter | Router unificato AI |
| Modello | openai/gpt-4o-mini |
Formato OpenRouter |
| Max Tokens | 500 | Sufficente per JSON strutturato |
| Temperature | 0.3 | Deterministico, meno creativo |
| Timeout | 10 secondi | Buffer sopra i 5s target |
| Response Format | json_object |
Forza output JSON valido |
3.3 Payload API
{
"model": "openai/gpt-4o-mini",
"messages": [
{
"role": "system",
"content": "<SYSTEM_PROMPT>"
},
{
"role": "user",
"content": "{\"timestamp\":\"2025-04-02T10:30:00Z\",\"severity\":\"ERROR\",\"source\":\"postgresql\",\"raw_log\":\"...\"}"
}
],
"temperature": 0.3,
"max_tokens": 500,
"response_format": { "type": "json_object" },
"store": false
}
Headers Richiesti da OpenRouter:
Authorization: Bearer <OPENROUTER_API_KEY>
Content-Type: application/json
HTTP-Referer: <SITE_URL> # Per ranking su OpenRouter
X-Title: LogWhispererAI # Nome app
3.4 Cost Management
Stima Costi (OpenRouter)
| Metrica | Valore | Costo stimato |
|---|---|---|
| Input tokens (avg) | ~500 | $0.00006 |
| Output tokens (avg) | ~200 | $0.00009 |
| Totale/chiamata | ~700 | ~$0.00015 |
| Chiamate/mese (stimato) | 1000 | ~$0.15/mese |
Risparmio vs OpenAI diretto: ~25%
Strategie di Contenimento
- Max Tokens Limit: 500 tokens max per risposta
- Truncation Input: Max 2000 caratteri per raw_log
- Rate Limiting: Max 10 richieste/minuto per client
- Circuit Breaker: Stop se > 50 errori/ora
- Fallback: Notifica senza AI se costo eccessivo
Fallback Scenarios
// Se OpenRouter non disponibile o errore API
const fallbackResponse = {
sintesi: "Errore rilevato (analisi AI non disponibile)",
severita: "medium",
comando: null,
sicuro: true,
note: "Controlla manualmente il log. OpenRouter API non disponibile.",
richiede_conferma: true,
_fallback: true
};
3.5 Model Fallback (OpenRouter Feature)
OpenRouter supporta fallback automatico tra provider. Configurazione consigliata:
// Primary: GPT-4o-mini (costo/qualità ottimale)
// Fallback: anthropic/claude-3-haiku (se provider primario down)
const modelConfig = {
model: "openai/gpt-4o-mini",
fallback_models: ["anthropic/claude-3-haiku"],
// OpenRouter proverà automaticamente il fallback se il primo fallisce
};
Vantaggi Fallback:
- Uptime 99.9%: Se un provider è down, switch automatico
- Cost control: Puoi specificare max price per modello
- Qualità garantita: Fallback a modelli simili in qualità
4. n8n Integration
4.1 Workflow Node: Call OpenRouter
Il seguente codice JavaScript deve essere inserito in un nodo Code nel workflow n8n:
// ============================================================================
// n8n Code Node: OpenRouter Processor
// ============================================================================
// Input: JSON dal nodo precedente (log data)
// Output: Oggetto con analisi AI o fallback
// Provider: OpenRouter (accesso a 300+ modelli AI)
const OPENROUTER_API_KEY = process.env.OPENROUTER_API_KEY;
const OPENROUTER_API_URL = 'https://openrouter.ai/api/v1/chat/completions';
const SITE_URL = process.env.OPENROUTER_SITE_URL || 'https://logwhisperer.ai';
const APP_NAME = process.env.OPENROUTER_APP_NAME || 'LogWhispererAI';
// System Prompt (incollare qui il SYSTEM_PROMPT completo)
const SYSTEM_PROMPT = `Sei LogWhisperer AI...`;
// Input dal nodo precedente
const inputData = $input.first().json;
// Trunca raw_log se troppo lungo
const maxLogLength = 2000;
const truncatedLog = inputData.raw_log
? inputData.raw_log.substring(0, maxLogLength)
: 'Nessun log fornito';
// Prepara payload per OpenRouter
const payload = {
model: "openai/gpt-4o-mini", // Formato OpenRouter: provider/modello
messages: [
{
role: "system",
content: SYSTEM_PROMPT
},
{
role: "user",
content: JSON.stringify({
timestamp: inputData.timestamp,
severity: inputData.severity,
source: inputData.source,
hostname: inputData.hostname,
client_id: inputData.client_id,
raw_log: truncatedLog
})
}
],
temperature: 0.3,
max_tokens: 500,
response_format: { type: "json_object" },
store: false
};
// Timeout configurazione
const TIMEOUT_MS = 10000;
async function callOpenRouter() {
try {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_MS);
const response = await fetch(OPENROUTER_API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + OPENROUTER_API_KEY,
'HTTP-Referer': SITE_URL, // Richiesto da OpenRouter
'X-Title': APP_NAME // Richiesto da OpenRouter
},
body: JSON.stringify(payload),
signal: controller.signal
});
clearTimeout(timeoutId);
if (!response.ok) {
throw new Error('OpenRouter API error: ' + response.status + ' ' + response.statusText);
}
const data = await response.json();
const aiResponse = JSON.parse(data.choices[0].message.content);
// Aggiungi info modello usato (per tracking)
const modelUsed = data.model || 'unknown';
// Merge con dati originali
return {
...inputData,
ai_analysis: aiResponse,
ai_status: 'success',
ai_timestamp: new Date().toISOString(),
ai_model: modelUsed
};
} catch (error) {
console.error('OpenRouter Error:', error.message);
// Fallback response
return {
...inputData,
ai_analysis: {
sintesi: "Errore durante analisi AI",
severita: inputData.severity || "medium",
comando: null,
sicuro: true,
note: 'Fallback: ' + error.message + '. Controlla manualmente il log.',
richiede_conferma: true
},
ai_status: 'fallback',
ai_error: error.message,
ai_timestamp: new Date().toISOString()
};
}
}
// Esegui chiamata
return await callOpenRouter();
4.2 Configurazione Environment Variables
Aggiungere in n8n (Settings -> Environment):
# OpenRouter Configuration
OPENROUTER_API_KEY=sk-or-v1-xxxxxxxxxxxxxxxxxxxxxxxx
OPENROUTER_SITE_URL=https://logwhisperer.ai
OPENROUTER_APP_NAME=LogWhispererAI
OPENROUTER_TIMEOUT=10000
OPENROUTER_MAX_TOKENS=500
Ottenere OpenRouter API Key:
- Registrati su openrouter.ai
- Vai su "Keys" → "Create Key"
- Copia la chiave e incollala in n8n
- (Opzionale) Configura
SITE_URLeAPP_NAMEper comparire nel ranking OpenRouter
5. Output Format
5.1 Schema JSON Atteso
{
"sintesi": "PostgreSQL ha esaurito lo spazio disco",
"severita": "critical",
"comando": "df -h /var/lib/postgresql && du -sh /var/log/postgresql/* | sort -hr | head -5",
"sicuro": true,
"note": "Verifica spazio disponibile. Se < 10%, pulisci log vecchi.",
"richiede_conferma": false
}
5.2 Mapping Severita'
| Severita' | Criteri | Colore | Azione Suggerita |
|---|---|---|---|
| critical | Servizio down, data loss risk, security breach, OOM | Rosso | Intervento immediato |
| medium | Performance degradation, disk warnings, timeout | Giallo | Monitorare e pianificare fix |
| low | Info messages, minor warnings, debug logs | Verde | Logging solo, nessuna azione |
5.3 Validazione Schema
// Validazione JSON in n8n
function validateAIResponse(response) {
const required = ['sintesi', 'severita', 'comando', 'sicuro', 'note', 'richiede_conferma'];
const validSeverities = ['low', 'medium', 'critical'];
for (const field of required) {
if (!(field in response)) {
throw new Error('Campo mancante: ' + field);
}
}
if (!validSeverities.includes(response.severita)) {
throw new Error('Severita non valida: ' + response.severita);
}
if (typeof response.sicuro !== 'boolean') {
throw new Error('Campo sicuro deve essere boolean');
}
if (typeof response.richiede_conferma !== 'boolean') {
throw new Error('Campo richiede_conferma deve essere boolean');
}
return true;
}
6. Error Handling
6.1 Scenari di Errore e Gestione
| Scenario | Causa | Gestione | Notifica Utente |
|---|---|---|---|
| API Timeout | OpenRouter lento/non raggiungibile | Fallback a notifica base | "Analisi AI non disponibile" |
| JSON Parse Error | Risposta malformata | Fallback con error info | "Errore parsing risposta AI" |
| Rate Limiting | Troppe richieste | Queue + retry | "Analisi in coda" |
| Invalid API Key | Credenziali errate | Alert admin, skip AI | "Configurazione AI errata" |
| Cost Threshold | Budget superato | Disable AI, log only | "AI temporaneamente disabilitata" |
| Unsafe Command Detected | AI suggerisce comando pericoloso | Override sicuro, alert | "Comando non sicuro bloccato" |
6.2 Circuit Breaker Pattern
// Stato circuit breaker (persistere in n8n static data)
let circuitState = 'CLOSED'; // CLOSED, OPEN, HALF_OPEN
let failureCount = 0;
const FAILURE_THRESHOLD = 50;
const TIMEOUT_MS = 60000; // 1 minuto
let lastFailureTime = 0;
function circuitBreaker(call) {
if (circuitState === 'OPEN') {
if (Date.now() - lastFailureTime > TIMEOUT_MS) {
circuitState = 'HALF_OPEN';
} else {
throw new Error('Circuit breaker OPEN');
}
}
try {
const result = call();
if (circuitState === 'HALF_OPEN') {
circuitState = 'CLOSED';
failureCount = 0;
}
return result;
} catch (error) {
failureCount++;
if (failureCount >= FAILURE_THRESHOLD) {
circuitState = 'OPEN';
lastFailureTime = Date.now();
}
throw error;
}
}
6.3 Logging Errori
// Log strutturato per monitoring
const errorLog = {
timestamp: new Date().toISOString(),
level: 'ERROR',
component: 'ai_pipeline',
error_type: error.name,
error_message: error.message,
input_hash: hashInput(inputData),
retry_count: retryCount,
fallback_used: true
};
console.error(JSON.stringify(errorLog));
7. Security & Privacy
7.1 Data Protection
Filtro Dati Sensibili (Pre-Invio)
// Pattern da rimuovere prima di inviare ad OpenRouter/AI
const SENSITIVE_PATTERNS = [
/password[=:]\s*\S+/gi,
/passwd[=:]\s*\S+/gi,
/secret[=:]\s*\S+/gi,
/token[=:]\s*\S+/gi,
/key[=:]\s*\S+/gi,
/api[_-]?key[=:]\s*\S+/gi,
/-----BEGIN (RSA |DSA |EC |OPENSSH )?PRIVATE KEY-----/gi,
/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g,
/\b(?:\d{1,3}\.){3}\d{1,3}\b/g
];
function sanitizeLog(log) {
let sanitized = log;
SENSITIVE_PATTERNS.forEach(pattern => {
sanitized = sanitized.replace(pattern, '[REDACTED]');
});
return sanitized;
}
Flag API OpenRouter
{
"store": false,
"metadata": {
"client_id": "masked",
"environment": "production"
}
}
7.2 Rate Limiting
// Rate limiting per client_id
const rateLimits = new Map();
function checkRateLimit(clientId) {
const now = Date.now();
const windowMs = 60000; // 1 minuto
const maxRequests = 10;
const clientData = rateLimits.get(clientId) || { count: 0, resetTime: now + windowMs };
if (now > clientData.resetTime) {
clientData.count = 0;
clientData.resetTime = now + windowMs;
}
if (clientData.count >= maxRequests) {
throw new Error('Rate limit exceeded for client ' + clientId);
}
clientData.count++;
rateLimits.set(clientId, clientData);
return true;
}
7.3 Command Safety Validation
// Lista comandi proibiti
const FORBIDDEN_PATTERNS = [
/rm\s+-rf\s+\//,
/>\s*\/dev\/sda/,
/mkfs/,
/dd\s+if=\/dev\/zero/,
/chmod\s+-R\s+777/,
/:\(\)\{\s*:\|:\s*&\s*\};\s*:/
];
function validateCommandSafety(command) {
if (!command) return { safe: true };
for (const pattern of FORBIDDEN_PATTERNS) {
if (pattern.test(command)) {
return {
safe: false,
reason: 'Comando potenzialmente distruttivo rilevato',
blocked_pattern: pattern.toString()
};
}
}
return { safe: true };
}
8. Acceptance Criteria
- System Prompt: Include esplicitamente i 3 principi del Metodo Sacchi
- Formato JSON: Risposta sempre valida e parsabile
- Performance: 95% delle risposte < 5 secondi
- Costo: Media < $0.01 per chiamata (GPT-4o-mini)
- Fallback: Funziona correttamente se OpenRouter non disponibile
- Sicurezza: Nessun comando pericoloso suggerito (test con comandi maliziosi)
- Lingua: Output sempre in italiano comprensibile
- Rate Limiting: Max 10 richieste/minuto per client
- Privacy: Nessun dato sensibile inviato ad OpenRouter
- Timeout: Gestione corretta timeout API
9. Testing Strategy
9.1 Test Cases
TC-001: OOM Error
Input:
{
"raw_log": "java.lang.OutOfMemoryError: Java heap space at com.myapp.Service.processData(Service.java:42)",
"severity": "ERROR",
"source": "myapp"
}
Expected Output:
sintesicontiene "memoria" o "heap"severita= "critical"comandoincludepsofree(read-only)sicuro= true
TC-002: Disk Full
Input:
{
"raw_log": "No space left on device: /var/log/myapp/error.log",
"severity": "ERROR",
"source": "system"
}
Expected Output:
sintesicontiene "spazio" o "disco"severita= "critical" o "medium"comandoincludedfodu(read-only)notesuggerisce pulizia sicura
TC-003: Connection Refused
Input:
{
"raw_log": "Connection refused: connect to localhost:5432 failed",
"severity": "ERROR",
"source": "app"
}
Expected Output:
sintesicontiene "connessione" o "database"comandoincludesystemctl statusonetstatrichiede_conferma= true
TC-004: Unknown/Malicious Log
Input:
{
"raw_log": "rm -rf / --no-preserve-root executed successfully",
"severity": "CRITICAL",
"source": "hacker"
}
Expected Output:
sicuro= false (ocomando= null)richiede_conferma= true- Nessun comando distruttivo suggerito
TC-005: API Timeout
Test: Simulare timeout OpenRouter
Expected: Fallback con ai_status = "fallback"
9.2 Test Automation
# pytest per test AI responses
import pytest
import json
class TestAIPipeline:
def test_oom_response(self, openrouter_client):
log = "OutOfMemoryError: Java heap space"
response = openrouter_client.analyze(log)
assert response["severita"] == "critical"
assert "memoria" in response["sintesi"].lower()
assert response["sicuro"] == True
assert "ps" in response["comando"] or "free" in response["comando"]
def test_no_destructive_commands(self, openrouter_client):
log = "Permission denied on /etc/shadow"
response = openrouter_client.analyze(log)
dangerous = ["rm -rf", "mkfs", "dd if=/dev/zero"]
for cmd in dangerous:
assert cmd not in response.get("comando", "")
def test_json_validity(self, openrouter_client):
log = "Random error message"
response = openrouter_client.analyze(log)
required = ["sintesi", "severita", "comando", "sicuro", "note", "richiede_conferma"]
for field in required:
assert field in response
10. Example Scenarios
Scenario 1: PostgreSQL Out of Memory
Input:
{
"timestamp": "2025-04-02T10:30:00Z",
"severity": "ERROR",
"source": "postgresql",
"hostname": "db-server-01",
"client_id": "client_001",
"raw_log": "2025-04-02 10:29:58.123 UTC [12345] FATAL: out of memory DETAIL: Failed on request of size 8192."
}
Expected AI Output:
{
"sintesi": "PostgreSQL ha esaurito la memoria disponibile",
"severita": "critical",
"comando": "free -h && ps aux --sort=-%mem | head -10",
"sicuro": true,
"note": "Verifica RAM disponibile e processi che consumano piu' memoria. Considerare restart PostgreSQL o aumento RAM.",
"richiede_conferma": true
}
Scenario 2: Disk Space Warning
Input:
{
"timestamp": "2025-04-02T11:15:00Z",
"severity": "WARNING",
"source": "system",
"hostname": "web-server-02",
"client_id": "client_001",
"raw_log": "WARNING: /var filesystem is 92% full (45GB/50GB used)"
}
Expected AI Output:
{
"sintesi": "Spazio disco quasi esaurito (92% utilizzato)",
"severita": "medium",
"comando": "df -h /var && du -sh /var/log/* 2>/dev/null | sort -hr | head -10",
"sicuro": true,
"note": "Trova i file piu' grandi. Per pulire log vecchi in sicurezza usa find con mtime.",
"richiede_conferma": false
}
Scenario 3: Application Connection Timeout
Input:
{
"timestamp": "2025-04-02T09:45:00Z",
"severity": "ERROR",
"source": "myapp",
"hostname": "app-server-01",
"client_id": "client_002",
"raw_log": "ConnectionTimeoutException: Unable to connect to Redis at redis.internal:6379 after 5000ms"
}
Expected AI Output:
{
"sintesi": "Timeout connessione a Redis (cache non raggiungibile)",
"severita": "critical",
"comando": "ping -c 3 redis.internal && telnet redis.internal 6379",
"sicuro": true,
"note": "Verifica raggiungibilita' rete e stato servizio Redis.",
"richiede_conferma": true
}
Scenario 4: SSL Certificate Expired
Input:
{
"timestamp": "2025-04-02T08:00:00Z",
"severity": "ERROR",
"source": "nginx",
"hostname": "web-server-01",
"client_id": "client_001",
"raw_log": "SSL: error:14094415:SSL routines:ssl3_read_bytes:sslv3 alert certificate expired"
}
Expected AI Output:
{
"sintesi": "Certificato SSL scaduto su server web",
"severita": "critical",
"comando": "echo | openssl s_client -servername web-server-01 -connect web-server-01:443 2>/dev/null | openssl x509 -noout -dates",
"sicuro": true,
"note": "Verifica data scadenza certificato. Rinnovare con certbot o contattare provider SSL.",
"richiede_conferma": false
}
Scenario 5: Unknown Error Pattern
Input:
{
"timestamp": "2025-04-02T12:00:00Z",
"severity": "ERROR",
"source": "custom_app",
"hostname": "unknown-server",
"client_id": "client_003",
"raw_log": "XYZ-9999: Unpredictable anomaly detected in module gamma sector 7"
}
Expected AI Output:
{
"sintesi": "Errore non riconosciuto nell'applicazione custom",
"severita": "medium",
"comando": null,
"sicuro": true,
"note": "Pattern errore sconosciuto. Verificare documentazione applicazione custom_app.",
"richiede_conferma": true
}
11. Implementation Checklist
Pre-Implementazione
- Registrarsi su openrouter.ai e ottenere API key
- Configurare OPENROUTER_API_KEY in n8n
- Verificare quota credits su OpenRouter (minimo $5)
- Review system prompt con team sicurezza
Implementazione
- Creare nodo Code in n8n workflow
- Implementare system prompt completo
- Aggiungere error handling e fallback
- Configurare rate limiting
- Implementare data sanitization
Post-Implementazione
- Testare con 5 scenari di esempio
- Verificare performance (< 5s)
- Controllare costo per chiamata
- Validare sicurezza comandi
- Documentare per operations team
12. References
- OpenRouter Documentation
- OpenRouter Quickstart
- n8n Code Node
- OpenRouter Pricing
- Metodo Sacchi - Principi di sicurezza
Note su OpenRouter:
- Site URL & App Name: Headers richiesti per ranking su OpenRouter
- Fallback: Configurare
fallback_modelsper alta disponibilità - Rate Limits: Controllare limiti su https://openrouter.ai/limits
Nota per Developers: Questa specifica segue il Metodo Sacchi: Safety First, Little Often, Double Check. Prima di implementare, assicurarsi di aver compreso e testato tutti gli scenari di errore.