Kibana не звонит: написали скрипт алертинга поверх Elasticsearch своими руками
Kibana 3 умеет только показывать. Чтобы получать письма при всплеске ошибок, написали простой Python-скрипт с опросом Elasticsearch раз в минуту.
Отсутствие встроенного алертинга в Kibana/Elasticsearch стимулирует разработку внешних решений
Когда мы разворачивали ELK в продакшне летом, у нас был один открытый вопрос: Kibana 3 красиво показывает логи, но уведомлений не отправляет. Тогда мы оставили это на Zabbix - он смотрит за числовыми метриками и при проблемах будит дежурного. Но у Zabbix есть слепое пятно: он не знает, что творится внутри лог-потока. Количество ERROR-записей в Elasticsearch - не его дело.
Прошло четыре месяца, и это слепое пятно начало нас беспокоить всерьёз.
Откуда взялась задача
У одного из клиентов - Java-приложение с внешними интеграциями. Интеграции периодически падают молча: HTTP 500 снаружи, стектрейс внутри лога, но сервис в целом работает, метрики по CPU/памяти нормальные, Zabbix молчит. Дежурный узнавал о проблеме от клиента заказчика, а не от инструментов - что примерно вдвое хуже по любой метрике.
Kibana на дашборде это всё прекрасно видит: есть виджет с количеством ERROR за последние N минут, есть временна`я шкала. Но смотреть на дашборд в три ночи никто не будет.
Значит, нужен что-то, что опрашивает Elasticsearch и само присылает письмо когда плохо.
Что смотрели, что не нашли
Поискали готовые решения. На GitHub нашлось несколько проектов в разной степени заброшенности - ни один не тянул на production-ready. Kibana 3 плагины смотрели - алертинг там не предусмотрен архитектурно, это фронтенд без серверной логики. Elasticsearch сам по себе тоже не отправляет уведомлений - это поисковый движок, не система мониторинга.
В итоге решили написать свой скрипт. Задача маленькая, требования простые - не надо строить систему, надо закрыть дыру.
Скрипт: минута, запрос, письмо
Python, минимум зависимостей - только requests для HTTP и стандартная библиотека для отправки почты. Логика прямолинейная:
cron раз в минуту -> скрипт -> запрос к Elasticsearch ->
если count > порог -> sendmail
Запрос к Elasticsearch - обычный count-запрос с временным фильтром «последние 5 минут» и фильтром поlog_level: ERROR. Elasticsearch HTTP API отвечает JSON с полемcount` - дальше сравниваем с порогом и решаем отправлять или нет.
Несколько вещей которые пришлось продумать сразу:
Подавление повторов. Если ошибки идут поток, не надо слать письмо каждую минуту. Сделали состояние: файл с временно`й меткой последней отправки. Следующее письмо - не раньше чем через 15 минут, даже если порог всё ещё превышен.
Разные пороги для разных индексов. У клиента несколько приложений, каждое пишет в свой индекс. Конфиг сделали в виде простого JSON-файла: список проверок, у каждой - паттерн индекса, поле уровня, порог, получатели.
Формат письма. Первая версия слала просто число: «Ошибок: 47». Оказалось бесполезно - непонятно какое приложение, что за ошибки. Доработали: добавили в письмо несколько примеров из той же выборки, первые три сообщения из ERROR-документов за тот же период. Это дало контекст без необходимости идти в Kibana для понимания масштаба.
Тайм-ауты. Elasticsearch иногда думает дольше обычного, особенно если индекс большой и запрос чуть сложнее. Поставили тайм-аут запроса 10 секунд и явный выход по коду ошибки - чтобы зависший cron-запрос не накапливался.
Как выглядит в работе
Скрипт крутится на том же хосте, где Logstash и Kibana - там же, в рамках управляемой инфраструктуры. Cron-запись простая, запуск от отдельного системного пользователя без лишних прав.
За первую неделю поймали два реальных инцидента раньше, чем о них сообщили. Один - именно та ситуация с падением интеграции, ради которой всё затевалось. Другой - неожиданный: ночная задача по генерации отчётов начала сыпать ClassNotFoundException из-за обновления библиотеки, которое разработчики выкатили без предупреждения. Без алертинга это обнаружили бы утром.
Что это такое и чем не является
Называть это «системой алертинга» неловко - это скрипт на 150 строк с cron-ом. Он не умеет эскалаций, не умеет дежурных расписаний, не умеет групп получателей с ack-ом. Для этого есть Zabbix и PagerDuty.
Но для задачи «сообщить команде что в логах что-то идёт не так» - справляется. Порог настраивается под каждое приложение, повторы подавляются, письма информативные. На текущем масштабе - достаточно.
Ограничение другое: скрипт проверяет только то, что мы явно описали в конфигурационном файле. Если появляется новое приложение - нужно добавить запись руками. Нет никакой автоматической детекции аномалий, нет machine learning, нет вероятностных порогов. Просто count > N.
Мы это принимаем. Инструмент сделан за два дня, закрывает конкретную дыру и не претендует на большее. Если задача вырастет - будем смотреть что к тому моменту появится из нормальных инструментов. Пока - вот этот скрипт, и он работает.