Мини-отчёт за неделю: как мы на скорую руку собрали себе "уведомлятор" в Telegram о состоянии нашего проекта
...и теперь спим спокойно. Ну, почти.
Короче, сидим мы в пятницу вечером, деплоим очередной релиз. Всё зелёное, тесты проходят, CI радостно мигает галочками. Ложимся спать как приличные люди. Просыпаемся — а в проде уже 4 часа лежит один из сервисов. Пользователи пишут. Менеджер пишет. Мама пишет (ладно, мама не пишет, но ощущение такое). Мы посмотрели друг на друга и сказали: "Хватит. Нам нужен бот."
Не тот бот, который стоит $200/мес и присылает 400 писем на почту, которую никто не читает. А свой, тёплый, ламповый — прямо в Telegram, прямо в рабочий чат, с понятными сообщениями на человеческом языке.
Вот что получилось за неделю. Разбираем по шагам.
Шаг 1. Определили, что вообще мониторим Прежде чем писать код, сели и выписали всё, что может сломаться (спойлер — всё): → HTTP-эндпоинты: жив ли сервер, отвечает ли API, какие статус-коды летят → Время ответа: если ручка начала отвечать 8 секунд вместо 200мс — это проблема, даже если статус 200 → Ошибки в логах: трейсбеки, panic, unhandled exception — всё, что пахнет бедой → Ресурсы: CPU, RAM, диск. Когда диск заканчивается в 3 ночи — это отдельный вид боли → Бизнес-метрики: количество заказов/регистраций резко упало? Возможно, что-то отвалилось, даже если серверу "нормально"
Шаг 2. Подняли Telegram-бота Зашли к @BotFather, создали бота за 30 секунд. Получили токен. Дальше — дело техники. Стек выбрали максимально простой:
→ Python + aiogram 3 (потому что асинхронно и удобно) → aiohttp для health-check запросов → APScheduler для периодических проверок → Docker, чтобы это всё жило рядом с основным проектом Структура проекта получилась такая:
monitoring-bot/ ├── bot.py # точка входа ├── checkers/ │ ├── http_check.py # проверка эндпоинтов │ ├── log_watcher.py # парсинг логов │ └── system_check.py # CPU/RAM/диск ├── notifier.py # отправка в Telegram ├── config.py # все настройки в одном месте ├── docker-compose.yml └── .env
Чисто, понятно, расширяемо. Никакого оверинжиниринга.
Шаг 3. Написали чекеры HTTP Health Check — самый базовый и самый полезный. Раз в 30 секунд дёргаем список URL-ов и смотрим, что прилетает: async def check_endpoint(url: str, timeout: int = 10): try: async with aiohttp.ClientSession() as session: start = time.monotonic() async with session.get(url, timeout=aiohttp.ClientTimeout(total=timeout)) as resp: elapsed = time.monotonic() - start return { "url": url, "status": resp.status, "time_ms": round(elapsed * 1000), "ok": resp.status < 400 and elapsed < 5 } except Exception as e: return {"url": url, "status": 0, "time_ms": -1, "ok": False, "error": str(e)} Log Watcher — читаем лог-файл (или Docker-логи) и ищем ключевые слова. Без ML, без нейронок, просто if "ERROR" in line. И знаете что? Это работает.
System Check — psutil + shutil для диска. Три строчки, а сколько нервов экономит: import psutil, shutil
def get_system_stats(): disk = shutil.disk_usage("/") return { "cpu_percent": psutil.cpu_percent(interval=1), "ram_percent": psutil.virtual_memory().percent, "disk_free_gb": round(disk.free / (1024**3), 1), "disk_percent": round(disk.used / disk.total * 100, 1), } Шаг 4. Сделали уведомления человеческими Вот тут — самый важный момент. Мы не хотели получать сухие JSON-ы в чат. Мы хотели, чтобы бот разговаривал с нами как коллега (слегка паникующий, но информативный). Формат сообщений сделали такой: 🔴 АЛЯРМ! Проблема обнаружена
📍 Что: API /api/v1/orders ⏱ Время ответа: 12400ms (норма: <2000ms) 📊 Статус: 504 Gateway Timeout 🕐 Когда: 2026-04-05 03:14:22 MSK
💡 Последние 3 ошибки в логах: → context deadline exceeded → connection pool exhausted → retry limit reached
🔗 Grafana: [ссылка]
А когда всё хорошо, бот присылает дайджест раз в час: