{
  "name": "ispmanager Logs → GigaChat → Telegram Final",
  "nodes": [
    {
      "parameters": {
        "triggerTimes": {
          "item": [
            {
              "mode": "everyHour"
            }
          ]
        }
      },
      "id": "e3ab3c72-fb60-4d7b-ae73-77f7a4c2ffe8",
      "name": "Cron",
      "type": "n8n-nodes-base.cron",
      "typeVersion": 1,
      "position": [
        240,
        112
      ]
    },
    {
      "parameters": {
        "command": "#!/bin/bash\n\nMAX_LINES=10\n\nprint_section() {\n  echo \"\"\n  echo \"=== SOURCE: $1 ===\"\n}\n\n# Функция для поиска и вывода логов\nprocess_log() {\n  local file=$1\n  local label=$2\n  local pattern=$3\n  \n  if [ -f \"$file\" ] && [ -s \"$file\" ]; then\n    local content=$(grep -E \"$pattern\" \"$file\" | tail -n $MAX_LINES)\n    if [ ! -z \"$content\" ]; then\n      print_section \"$label\"\n      echo \"$content\"\n    fi\n  fi\n}\n\n# --- СИСТЕМНЫЕ МЕТРИКИ ---\nprint_section \"SYSTEM STATUS\"\necho \"Load Average: $(uptime | awk -F'load average:' '{ print $2 }')\"\necho \"Memory: $(free -h | awk '/^Mem:/ {print $3 \"/\" $2 \" used\"}')\"\necho \"Disk Usage: $(df -h / | awk 'NR==2 {print $5 \" used on /\"}')\"\n\n# --- ЛОГИ ISPMANAGER ---\n#for f in /usr/local/mgr5/var/*.log; do\n#  process_log \"$f\" \"ispmanager / $(basename \"$f\")\" \"(ERROR|CRITICAL|PANIC|FATAL|exception|denied|timeout|refused|segmentation fault|oom-killer)\"\n#done\n\n# --- NGINX ---\nfor f in /var/log/nginx/*error.log; do\n  process_log \"$f\" \"nginx / $(basename \"$f\")\" \"(error|crit|alert|emerg)\"\ndone\n\n# --- PHP-FPM ---\nfor f in /var/log/php*-fpm.log; do\n  process_log \"$f\" \"php-fpm / $(basename \"$f\")\" \"(ERROR|WARNING|child exited|segfault|crash)\"\ndone\n\n# --- EXIM ---\nprocess_log \"/var/log/exim4/mainlog\" \"exim / mainlog\" \"(panic|error|rejected|failed)\"\n\n# --- DATABASE ---\nif [ -f /var/log/mysql/error.log ]; then\n  process_log \"/var/log/mysql/error.log\" \"mysql / error.log\" \".\"\nelif [ -f /var/log/mariadb/mariadb.log ]; then\n  process_log \"/var/log/mariadb/mariadb.log\" \"mariadb / mariadb.log\" \"(error|critical|innodb)\"\nfi"
      },
      "id": "c2a3e539-a98e-44fe-9915-af3c4021b3c0",
      "name": "Read & Filter ispmanager Logs",
      "type": "n8n-nodes-base.ssh",
      "typeVersion": 1,
      "position": [
        432,
        112
      ],
      "credentials": {
        "sshPassword": {
          "id": "default",
          "name": "SSH Password Default"
        }
      }
    },
    {
      "parameters": {
        "functionCode": "const raw = $json.stdout || '';\nconst cleaned = raw.trim();\n\nif (!cleaned) return [];\n\nfunction simpleHash(str) {\n  let hash = 5381;\n  for (let i = 0; i < str.length; i++) {\n    hash = ((hash << 5) + hash) + str.charCodeAt(i);\n    hash = hash & hash;\n  }\n  return hash.toString();\n}\n\nconst currentHash = simpleHash(cleaned);\nconst data = this.getWorkflowStaticData('global');\nconst isRepeat = data.lastHash === currentHash;\ndata.lastHash = currentHash;\n\n// Берем последние символы (tail-style), чтобы не потерять свежие ошибки\nconst MAX_LENGTH = 12000;\nconst logs = cleaned.length > MAX_LENGTH\n  ? \"...[LOGS TRUNCATED]...\\n\" + cleaned.slice(-MAX_LENGTH)\n  : cleaned;\n\nconst today = new Date().toISOString().slice(0, 10);\n\nreturn [{\n  json: {\n    logs,\n    isRepeat,\n    sessionId: `ispmanager_server_1_${today}`,\n    analysis_date: new Date().toISOString()\n  }\n}];"
      },
      "id": "57058f7c-ace0-45ab-9979-6f788fa97ca4",
      "name": "Prepare Logs",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        672,
        112
      ]
    },
    {
      "parameters": {
        "contextWindowLength": 10
      },
      "id": "f22b1388-ae87-4587-9e72-e4c1a542855f",
      "name": "Simple Memory (Analysis History)",
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "typeVersion": 1,
      "position": [
        944,
        320
      ]
    },
    {
      "parameters": {
        "prompt": "=ВАЖНО:\n\nЕсли текущий анализ помечен как REPEAT (isRepeat = true):\n- не повторяй текст предыдущего отчёта\n- укажи, что проблемы сохраняются\n- усили рекомендации (эскалация)\n- добавь пометку [REPEAT]\n\nЕсли isRepeat = false — обычный анализ.\n\nТы senior SRE и эксперт по ispmanager.\n\nУ тебя есть доступ к долговременной памяти с ранее найденными проблемами.\n\nАЛГОРИТМ:\n1. Проанализируй логи по источникам.\n2. Определи ТОЛЬКО реальные проблемы.\n3. Сравни с памятью:\n   - если проблема уже была — отметь как ПОВТОР\n   - рекомендацию УСИЛЬ (эскалация)\n4. Если проблем нет — явно напиши об этом.\n\nSEVERITY:\n[CRITICAL] сервис недоступен / риск потери данных\n[HIGH] деградация / возможен даунтайм\n[MEDIUM] ошибка без немедленных последствий\n\nФОРМАТ (СТРОГО):\n\n🧩 Найденные проблемы:\n- [SEVERITY][NEW|REPEAT] краткое описание + пример строки лога\n\n🛠 Рекомендации:\n- конкретное действие (команда, конфиг, проверка)\n\n📌 Дополнительные замечания:\n- только если есть\n\nВАЖНОЕ ПРАВИЛО НАПИСАНИЯ:\n\nНазвание панели управления ВСЕГДА пиши строго как:\nispmanager\n\nЗапрещены любые варианты:\nISPManager, Ispmanager, ISPmanager, ISP Manager\n\nЕсли в логах или памяти встречается другое написание — нормализуй в ispmanager.\n\nЛоги:\n---\n{{ $json[\"logs\"] }}\n---\n\nФлаг повтора: {{ $json.isRepeat }}\n",
        "options": {}
      },
      "id": "bdd849b7-e825-46e4-9d1d-9ec09826717c",
      "name": "GigaChat",
      "type": "n8n-nodes-gigachat.gigaChat",
      "typeVersion": 1,
      "position": [
        880,
        112
      ],
      "credentials": {
        "gigaChatApi": {
          "id": "default",
          "name": "GigaChat Default"
        }
      }
    },
    {
      "parameters": {
        "functionCode": "let raw = $json.response || 'Отчёт пуст';\n\n// Нормализация\nraw = raw.replace(/\\bisp\\s*manager\\b/gi, 'ispmanager');\n\nfunction escapeHtml(text) {\n  return text\n    .replace(/&/g, \"&amp;\")\n    .replace(/</g, \"&lt;\")\n    .replace(/>/g, \"&gt;\");\n}\n\nconst lines = raw.split('\\n');\nlet out = [];\nlet inCode = false;\n\nfor (const line of lines) {\n  if (line.trim().startsWith('```')) {\n    inCode = !inCode;\n    out.push(inCode ? '<pre><code>' : '</code></pre>');\n    continue;\n  }\n\n  let formattedLine = inCode ? line : escapeHtml(line);\n\n  // Стилизация заголовков (если не в коде)\n  if (!inCode) {\n    formattedLine = formattedLine\n      .replace(/^🧩 (.+)/, '<b>$1</b>')\n      .replace(/^🛠 (.+)/, '<b>$1</b>')\n      .replace(/^📌 (.+)/, '<b>$1</b>');\n  }\n\n  out.push(formattedLine);\n}\n\nconst date = new Date().toISOString().replace('T', ' ').slice(0, 16);\nconst header = `<b>🧠 ispmanager · AIOps Report</b>\\n<code>${date} UTC</code>`;\nlet message = `${header}\\n\\n${out.join('\\n')}`;\n\nif (message.length > 4000) {\n  message = message.slice(0, 3900) + '\\n\\n<i>[Сообщение обрезано]</i>';\n}\n\nreturn [{ json: { message } }];"
      },
      "id": "6184c7ee-885a-4278-9db8-60d6cc78747a",
      "name": "Format Telegram Message",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        1184,
        112
      ]
    },
    {
      "parameters": {
        "chatId": "YOUR_CHAT_ID",
        "text": "={{ $json.message }}",
        "additionalFields": {
          "parse_mode": "HTML"
        }
      },
      "id": "b4ccb562-f234-49c7-b942-069dc3b1947c",
      "name": "Send to Telegram",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1,
      "position": [
        1376,
        112
      ],
      "credentials": {
        "telegramApi": {
          "id": "default",
          "name": "Telegram Default"
        }
      }
    }
  ],
  "connections": {
    "Cron": {
      "main": [
        [
          {
            "node": "Read & Filter ispmanager Logs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read & Filter ispmanager Logs": {
      "main": [
        [
          {
            "node": "Prepare Logs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Logs": {
      "main": [
        [
          {
            "node": "GigaChat",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "GigaChat": {
      "main": [
        [
          {
            "node": "Format Telegram Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Simple Memory (Analysis History)": {
      "ai_memory": [
        [
          {
            "node": "GigaChat",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "Format Telegram Message": {
      "main": [
        [
          {
            "node": "Send to Telegram",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  }
}