Бот для мониторинга веб-сервисов за полчаса: telegram + bash + cron

в 8:15, , рубрики: bash, cron, curl, linux, telegram, Ubuntu, Разработка под Linux, Системы обмена сообщениями

Бот для мониторинга веб-сервисов за полчаса: telegram + bash + cron - 1

Иногда нужно быстро сделать мониторинг для нового сервиса, а готовой инфраструктуры/экспертизы под рукой нет. В этом гайде мы за полчаса реализуем инструмент для мониторинга любых веб-сервисов, используя только встроенные средства ubuntu: bash, cron и curl. Для доставки оповещений будем использовать telegram.

«Вишенкой на торте» будет эмоциональное вовлечение пользователей. Проверено на людях — работает.

Когда мы в телемедицинском сервисе Доктор Рядом создали чат-бота для определения уровня стресса пользователей, нам понадобился мониторинг. За пару часов был сделан мини-проект, который не только отлично работает, но и добавляет позитива своими сообщениями.

Для начала, получим репозиторий со скриптами:

git clone https://github.com/rshekhovtsov/msms.git

Переходим в папку msms и далее работаем в ней.

Если telegram заблокирован, используйте прокси. Самый простой и надежный вариант — torsocks:

sudo apt install tor
sudo apt install torsocks

В качестве примера настроим в три шага мониторинг стартовой страницы google.com

ШАГ 1. Создаем бота в telegram и получаем id пользователя

  • В строке поиска контактов в telegram ищем @botfather:

    Бот для мониторинга веб-сервисов за полчаса: telegram + bash + cron - 2

  • Запускаем его кнопкой Start, вводим команду /newbot и отвечаем на вопросы. Нужно иметь ввиду, что name — это имя бота, которое будет отображаться пользователям, а username — уникален и должен завершаться на «bot»:

    Бот для мониторинга веб-сервисов за полчаса: telegram + bash + cron - 3

    Среди прочего, бот выдаст секретный токен для HTTP API, который нужно скопировать и сохранить в файл telegram-api-key.txt в папке msms.

  • Набираем в строке поиска telegram имя нашего бота, и запускаем его.
  • В качестве завершающего штриха, добавим себя в список получателей оповещений мониторинга:
    sudo chmod +x ./recipients-setup.sh
    torsocks ./recipients-setup.sh

    Скрипт выведет список последних обращений к боту, там должна быть одна строка с нашими id и именем в telegram. Берём этот id и сохраняем его в файле services/google-recipients.txt. Формат файла: каждая строка — один id. Пример:

    123456789
    987654321

Чтобы добавить нового получателя, нужно попросить его стартовать бота в telegram, запустить recipients-setup.sh и добавить id в файл.

ШАГ 2. Настраиваем мониторинг

Описание сервиса происходит путём создания ini-файла в папке serviсes. Нужно задать пять параметров:

  1. MSMS_SERVICE_NAME: наименование сервиса — будет использоваться в оповещениях и журнале мониторинга.
  2. MSMS_SERVICE_ENDPOINT: endpoint сервиса, на который мы будем обращаться curl'ом.
  3. MSMS_CURL_PARAMS: дополнительные параметры curl, см. пример ниже.
  4. MSMS_EXPECTED: ожидаемый ответ сервиса. Используется, если ответ короткий.
  5. MSMS_EXPECTED_FILE: имя файла с ожидаемым ответом сервиса. Если указан, перезаписывает MSMS_EXPECTED.
  6. MSMS_RECIPIENTS: файл со списком получателей оповещений.

Запрос на google.com возвращает фиксированный html c редиректом, будем использовать его как ожидаемый ответ сервера:

curl google.com > services/google-response.html

Создадим файл services/google.ini:

MSMS_SERVICE_NAME='google front page'

# service endpoint
MSMS_SERVICE_ENDPOINT='google.com'

# curl parameters
MSMS_CURL_PARAMS='-s --connect-timeout 3 -m 7'

# expected service response
MSMS_EXPECTED_FILE='google-response.html'

# recipients list file
MSMS_RECIPIENTS='google-recipients.txt'

В MSMS_CURL_PARAMS можно задать всё, что умеет curl, в том числе:

  1. Отключить сообщения curl, чтобы не засорять консоль и лог: -s
  2. Задать таймаут соединения с проверяемым сервисом (в секундах): --connect-timeout 3
  3. Задать таймаут получения ответа: -m 7
  4. Отключить проверку сертификата для SSL (например, если используется самоподписанный сертификат): --insecure
  5. Указать тип http-запроса: -X POST
  6. Указать заголовки: -H "Content-Type: application/json"
  7. Указать тело запроса в виде строки или файла. Пример для файла: -d @request.json

Мы отключили оповещения и задали таймауты 3 сек. на соединение и 7 сек. на получение ответа сервиса.

Внимание: указывайте значения параметров в одинарных кавычках, как в примере. К сожалению, bash в этом смысле довольно хрупок, и случайно залетевшая бабочка не там поставленная кавычка может привести к гибели вселенной сложно диагностируемым ошибкам.

Мы настроили мониторинг. Проверим, что все ОК:

sudo chmod +x ./monitoring.sh
torsocks ./monitoring.sh

Скрипт должен вывести сообщение вида:

2020-01-10 12:14:31
health-check "google front page": OK

ШАГ 3. Настраиваем расписание

Настроим расписание мониторинга в cron:

sudo crontab -e

Добавим строку для ежеминутной проверки google.com:

*/1 * * * * torsocks <ПУТЬ К ПАПКЕ РЕПОЗИТОРИЯ>/monitoring.sh >> <ПУТЬ К ПАПКЕ РЕПОЗИТОРИЯ>/monitoring.log 2>&1

Добавим каждый день в 11.00 оповещение, подтверждающее работоспособность самого мониторинга. Для этого передадим в скрипт параметр DAILY:

0 11 * * * torsocks <ПУТЬ К ПАПКЕ РЕПОЗИТОРИЯ>/monitoring.sh DAILY >> <ПУТЬ К ПАПКЕ РЕПОЗИТОРИЯ>/monitoring.log 2>&1

2>&1 — стандартный прием, перенаправляющий ошибки в основной поток вывода. В итоге, они тоже попадут в журнал мониторинга.

Сохраним изменения и подхватим их командой:

 sudo service cron reload

Подробнее о настройке cron можно почитать, например, здесь.

Таким образом, каждую минуту будет запускаться скрипт мониторинга, который будет через curl обращаться на google.com. Если полученный ответ отличается от ожидаемого, скрипт разошлёт по списку получателей оповещение в telegram. Журнал проверок ведётся в файле monitoring.log

Если нужно добавить еще один сервис, мы просто создаем новый ini-файл для него в папке services и, при необходимости, формируем отдельный список получателей. Всё остальное отработает автоматически.

Если проверяемый сервис стал недоступен, оповещение будет приходить ежеминутно. Если не получается быстро восстановить сервис, можно временно отключить уведомления в свойствах бота в telegram.

Теперь давайте подробно разберем дополнительные возможности и реализацию скриптов.

Шаблоны сообщений и эмоциональное вовлечение

Чтобы сделать общение с ботом более живым, мы назвали его Манечкой, добавили соответствующую картинку-аватар и привлекли профессиональных пиарщиков для создания текстов сообщений. Вы можете использовать наши наработки или поменять на свой вкус.

Например так:

Бот для мониторинга веб-сервисов за полчаса: telegram + bash + cron - 4
или даже так:

Бот для мониторинга веб-сервисов за полчаса: telegram + bash + cron - 5

Почему бы и нет?

Имя бота и аватарка задаются через @botfather.
Шаблоны сообщений находятся в папке templates:

  • curl-fail.txt: сообщение, отправляемое в случае, когда curl вернул ненулевой код ошибки. Обычно говорит о невозможности достучаться до сервиса.
  • daily.txt: ежедневное сообщение, подтверждающее, что мониторинг сервиса работает.
  • service-fail.txt: сообщение, отправляемое в случае, когда ответ сервиса отличается от ожидаемого.

Разберем возможности кастомизации на примере встроенных шаблонов сообщений.
В шаблонах используются эмодзи. К сожалению, habr их не отображает.
Для подбора эмодзи удобно использовать поиск на emojipedia.org:

Бот для мониторинга веб-сервисов за полчаса: telegram + bash + cron - 6

Подходящий символ просто копируете и вставляете в текст шаблона (это обычный unicode).

  1. curl-fail.txt:
    Котёнок,  помоги мне... 
    Не могу достучаться до сервиса "$MSMS_SERVICE_NAME" 
    `CURL EXIT CODE: $EXIT_CODE`

    Мы использовали заданное нами имя сервиса (переменная MSMS_SERVICE_NAME) и внутреннюю переменную скрипта с кодом завершения curl (EXIT_CODE). Также мы отформатировали сообщение, используя разметку telegram markdown: символы "`" обрамляют текст фиксированной ширины. Так как кавычки и апострофы являются служебными символами bash, мы экранируем их символом "". Имена переменных предваряем знаком "$".

    Результат:

    Бот для мониторинга веб-сервисов за полчаса: telegram + bash + cron - 7

  2. service-fail.txt:
    Котёнок, помоги мне... 
    Сервис "$MSMS_SERVICE_NAME" меня расстроил
    Он работает неправильно, вот что он мне отвечает:
    `$RESPONSE`

    Результат:

    Бот для мониторинга веб-сервисов за полчаса: telegram + bash + cron - 8

    Здесь мы используем еще одну переменную скрипта: RESPONSE. Она содержит ответ сервиса.

  3. daily.txt:
    Малыш, привет!
    У меня всё хорошо, cлежу за сервисом:
    "$MSMS_SERVICE_NAME" каждую минутку...
    А как у тебя дела?
    

    Результат:

    Бот для мониторинга веб-сервисов за полчаса: telegram + bash + cron - 9

Перейдем к реализации скриптов.

Скрипт мониторинга

monitoring.sh делает простой auto-discovery — берет все ini-файлы из папки services и для каждого выполняет основной скрипт с логикой проверки и рассылки оповещений:

#!/bin/bash
cd $(dirname "$0")/services

for service_ini  in $(ls *.ini); do
    bash ../msms.sh "$1" "$service_ini"
done

Для формирования ежесуточного сообщения о статусе мониторинга скрипту можно передать параметр DAILY.

Обратите внимание, что при старте скрипта текущая папка меняется на services. Это позволяет в ini-файлах указывать пути к файлам относительно services.

Скрипт проверки и рассылки оповещений

msms.sh содержит основную логику проверки сервиса и рассылки оповещений.

Работа с telegram:

# telegram endpoint
TG_API_URL="https://api.telegram.org/bot$(cat ../telegram-api-key.txt)/sendMessage"

#################################################################
# send message to telegram
# parameter: message text
#################################################################
function send_message {
    for chat_id  in $(cat ../$MSMS_RECIPIENTS); do
	curl -s -X POST --connect-timeout 10 $TG_API_URL -d chat_id=$chat_id -d parse_mode="Markdown" -d text="$1"
	echo
    done
}

Мы формируем URL для доступа к REST API telegram, используя сохраненный в файле секретный ключ.

Функция send_message использует curl для отправки сообщений на этот REST API, забирая id получателей из файла, указанного нами в ini. В отправляемых данных мы указываем, что используем разметку сообщений: parse_mode="Markdown".

Выведем текущие дату-время и загрузим ini-файл.

echo $(date '+%Y-%m-%d %H:%M:%S')

# load variables from .ini file:
. $2

Магическая строка . $2 выполняет переданный на вход вторым параметром ini-файл как обычный скрипт, занося заданные в нём значения в переменные окружения.

Загрузим ожидаемый ответ из файла, если задан параметр MSMS_EXPECTED_FILE:

if [ -n "$MSMS_EXPECTED_FILE" ]; then
 MSMS_EXPECTED="$(cat "$MSMS_EXPECTED_FILE")"
fi

Выполним проверку сервиса с отправкой оповещений, если нужно:

RESPONSE="$(eval curl $MSMS_CURL_PARAMS "$MSMS_SERVICE_ENDPOINT")"
EXIT_CODE=$?
if [[ $EXIT_CODE != 0 ]]; then
    echo health-check "$MSMS_SERVICE_NAME" FAILED: CURL EXIT WITH $EXIT_CODE
    MESSAGE="$(cat ../templates/curl-fail.txt)"
    MESSAGE=$(eval echo $MESSAGE)
    send_message "$MESSAGE"
elif [[ "$RESPONSE" != "$MSMS_EXPECTED" ]]; then
    echo health-check "$MSMS_SERVICE_NAME" FAILED: "$RESPONSE"
    MESSAGE="$(cat ../templates/service-fail.txt)"
    MESSAGE=$(eval echo $MESSAGE)
    send_message "$MESSAGE"
else
    echo health-check "$MSMS_SERVICE_NAME": OK
fi

Сначала присваиваем переменной RESPONSE результат выполнения команды curl для данного сервиса.

Выражение EXIT_CODE=$? кладет в переменную результат выполнения последней команды, т.е. curl. При необходимости отправки оповещения, считывается шаблон из соответствующего файла и осуществляется рассылка на получателей с помощью send_message.

Последний блок обрабатывает параметр DAILY:

if test "$1" = "DAILY"; then
    echo health-check "$MSMS_SERVICE_NAME" DAILY
    MESSAGE="$(cat ../templates/daily.txt)"
    MESSAGE=$(eval echo $MESSAGE)
    send_message "$MESSAGE"
fi

Он отправляется сообщение, подтверждающее работоспособность самого мониторинга.

Получение списка id пользователей

recipients-setup.sh обращается к API telegram для получения последних сообщений, адресованных боту:

curl -s https://api.telegram.org/bot$(cat telegram-api-key.txt)/getUpdates 
| python recipients-setup.py

Здесь используется магия python для красивого вывода списка. Это необязательно, можно просто взять нужный id из json, который выведет команда:

torsocks curl -s https://api.telegram.org/bot$(cat telegram-api-key.txt)/getUpdates

Заключение

Таким образом, вы можете использовать готовые скрипты и шаблоны сообщений, настраивая лишь наблюдаемые сервисы и списки для оповещений; можете создать новую «личность» для бота; а можете сделать своё решение на основе предложенного.

В качестве вариантов дальнейшего развития напрашивается конфигурирование и управление мониторингом в самом боте, но тут без python уже не обойтись. Если у кого-то дойдут руки раньше меня — вы знаете, куда заливать pull request :-)

Автор: Роман Шеховцов

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js