Как я писал скрипт: от идеи до рабочего инструмента

от автора

Пришла в голову  задача, которая на словах звучит просто. «Сделай скрипт, который смотрит логи и шлёт в Telegram»  ну что тут сложного? Bash, curl, пара if-ов. Час работы, не больше.

Изначально хотелось простого, чтобы скрипт анализирует системные логи и отправляет отчёт. Потом захотелось чуточку усложнить и добавить:

1.    Проверка ошибок в системных логах

2.    Контроль свободного места на диске

3.    Мониторинг состояния сервисов

4.    Анализ использования памяти

5.    Контроль попыток несанкционированного доступа

Пять пунктов. Каждый кажется несложным. Вместе они означали, что это уже не «скриптик на вечер», а полноценный инструмент. Что ж, поехали.

Для начала решил написать тестовую версию с минимальными фукциями:

#!/bin/bashTG_BOT_TOKEN="ваш_токен"TG_CHAT_ID="ваш_chat_id"send_telegram() {    local message="$1"    curl -s -X POST "https://api.telegram.org/bot$TG_BOT_TOKEN/sendMessage" \        -d chat_id="$TG_CHAT_ID" \        -d text="$message"}# Проверяем ошибки в journald за последний часERROR_COUNT=$(journalctl --since="1 hour ago" -p 3 2>/dev/null | grep -c "error|fail")if [ "$ERROR_COUNT" -gt 0 ]; then    send_telegram "Найдено ошибок: $ERROR_COUNT"else    send_telegram "Ошибок не найдено"fi

Запускаем. Молчание. Telegram не отвечает. Скрипт завершился без ошибок  значит, что-то всё-таки ушло, просто не туда куда надо, или вообще никуда.

Я решил проверить доступ к Telegram API вручную

curl -X POST "https://api.telegram.org/bot$TOKEN/sendMessage" \    -d chat_id="$CHAT_ID" \    -d text="Тест"

И когда  сообщение пришло стало понятно что API работает, проблема в скрипте. А если бы не пришло значит в токене и chat_id ошибка.

Дальше проверяем наличие зависимостей

which jq# Если нет — устанавливаем:sudo apt install jq -y

И тестируем каждую команду отдельно

Не запускайте весь скрипт, пока не убедились, что каждая его часть работает в терминале самостоятельно. Это скучно и медленно  зато экономит нервы.

В итоге я понял что когда писал скрип написал в полях временные значения заглушки.

В файле было вот это:

TG_BOT_TOKEN="123456789:ABC-DEF"    # ← фейковый токенTG_CHAT_ID="987654321"              # ← фейковый ID

Я тестировал скрипт с заглушками и и просто… забыл их заменить. Скрипт исправно стучался в Telegram с чужими данными и получал отказ. Curl ошибку не показывал он честно отправлял запрос, просто ответ меня не интересовал.

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

После этого открытия я выработал правило: если что-то не работает, не запускай весь скрипт целиком проверяй по частям.

Финальная версия: скрипт с меню

После всех поправок и переработок получился вот такой зверь  с цветным выводом, интерактивным меню и уведомлениями в Telegram при критических событиях.

#!/bin/bash# ===== НАСТРОЙКИ (ЗАМЕНИТЕ НА СВОИ) =====TG_BOT_TOKEN="ваш_токен"TG_CHAT_ID="ваш_chat_id"# Цвета для выводаRED='\033[0;31m'GREEN='\033[0;32m'YELLOW='\033[1;33m'BLUE='\033[0;34m'NC='\033[0m'send_to_telegram() {    curl -s -X POST "https://api.telegram.org/bot$TG_BOT_TOKEN/sendMessage" \        -d chat_id="$TG_CHAT_ID" \        -d text="$1" > /dev/null 2>&1}check_journal_errors() {    echo -e "${YELLOW}Проверка ошибок в journald...${NC}"    ERROR_COUNT=$(journalctl --since="1 hour ago" -p 3 2>/dev/null | grep -ci "error|fail")    if [ "$ERROR_COUNT" -eq 0 ]; then        echo -e "${GREEN}Ошибок не найдено${NC}"    else        echo -e "${RED}Найдено ошибок: $ERROR_COUNT${NC}"        journalctl --since="1 hour ago" -p 3 2>/dev/null | \            grep -i "error|fail" | sort | uniq -c | sort -nr | head -5    fi    read -p "Нажмите Enter..."}check_disk_space() {    echo -e "${YELLOW}Проверка диска...${NC}"    df -h | grep -E "^/dev/|Filesystem"    USAGE=$(df / | awk 'NR==2 {print $5}' | sed 's/%//')    if [ "$USAGE" -gt 85 ]; then        echo -e "${RED}КРИТИЧНО: диск заполнен на $USAGE%${NC}"        send_to_telegram "Критично: диск заполнен на $USAGE%"    elif [ "$USAGE" -gt 70 ]; then        echo -e "${YELLOW}ВНИМАНИЕ: диск заполнен на $USAGE%${NC}"    else        echo -e "${GREEN}Диск в порядке ($USAGE%)${NC}"    fi    read -p "Нажмите Enter..."}check_services() {    echo -e "${YELLOW}Проверка failed сервисов...${NC}"    FAILED=$(systemctl --failed --no-legend 2>/dev/null)    if [ -z "$FAILED" ]; then        echo -e "${GREEN}Все сервисы работают${NC}"    else        echo -e "${RED}Проблемные сервисы:${NC}"        echo "$FAILED"    fi    read -p "Нажмите Enter..."}check_memory() {    echo -e "${YELLOW}Проверка памяти...${NC}"    free -h    PERCENT=$(free | awk 'NR==2 {printf "%.0f", $3/$2 * 100}')    if [ "$PERCENT" -gt 90 ]; then        echo -e "${RED}КРИТИЧНО: память заполнена на $PERCENT%${NC}"    elif [ "$PERCENT" -gt 75 ]; then        echo -e "${YELLOW}ВНИМАНИЕ: память заполнена на $PERCENT%${NC}"    else        echo -e "${GREEN}Память в порядке ($PERCENT%)${NC}"    fi    read -p "Нажмите Enter..."}check_auth() {    echo -e "${YELLOW}Проверка неудачных входов...${NC}"    AUTH_LOG=""    [ -f /var/log/auth.log ] && AUTH_LOG="/var/log/auth.log"    [ -f /var/log/secure ]   && AUTH_LOG="/var/log/secure"    if [ -n "$AUTH_LOG" ]; then        FAIL_COUNT=$(grep "Failed password" "$AUTH_LOG" 2>/dev/null \            | grep "$(date '+%b %e')" | wc -l)        echo "Неудачных попыток за сегодня: $FAIL_COUNT"        if [ "$FAIL_COUNT" -gt 10 ]; then            send_to_telegram "$FAIL_COUNT неудачных попыток входа!"        fi    else        echo "Лог авторизации не найден"    fi    read -p "Нажмите Enter..."}full_check() {    send_to_telegram "Начата проверка системы на $(hostname)"    check_journal_errors    check_disk_space    check_services    check_memory    check_auth    send_to_telegram "Проверка завершена"    echo -e "${GREEN}Полная проверка завершена${NC}"    read -p "Нажмите Enter..."}show_menu() {    clear    echo -e "${BLUE}========================================${NC}"    echo -e "${BLUE}         СИСТЕМНЫЙ МОНИТОР              ${NC}"    echo -e "${BLUE}========================================${NC}"    echo -e "${GREEN}Хост: $(hostname)${NC}"    echo -e "${GREEN}Время: $(date '+%Y-%m-%d %H:%M:%S')${NC}"    echo ""    echo "1. Проверить ошибки journald"    echo "2. Проверить место на диске"    echo "3. Проверить failed сервисы"    echo "4. Проверить память"    echo "5. Проверить попытки входа"    echo "6. Полная проверка"    echo "0. Выход"    echo ""    echo -n "Выберите пункт: "}while true; do    show_menu    read choice    case $choice in        1) check_journal_errors ;;        2) check_disk_space ;;        3) check_services ;;        4) check_memory ;;        5) check_auth ;;        6) full_check ;;        0) echo "До свидания!"; exit 0 ;;        *) echo "Неверный выбор"; sleep 1 ;;    esacdone

Установка

# Создаём файл скриптаnano /usr/local/bin/system_monitor.sh# Вставляем код, заменяем токен и chat_id (серьёзно, замените)# Даём права на выполнениеchmod +x /usr/local/bin/system_monitor.sh# Запускаем/usr/local/bin/system_monitor.sh

Автозапуск через cron

Если хочется, чтобы скрипт гонял проверки сам добавляем в cron:

crontab -e# Добавляем строку для запуска каждый час:0 * * * * /usr/local/bin/system_monitor.sh

Осторожно: в режиме cron интерактивное меню не работает — нужно будет вызывать конкретные функции напрямую, без цикла show_menu.

Что я вынес из этого

Если честно, половину этих выводов можно было прочитать в любом руководстве. Но одно дело читать, другое  самому наступить на грабли и потом кивать: «ну да, предупреждали же».

1.    Базовые вещи ломаются первыми. Токен, chat_id, права на файл, наличие curl проверяйте это в первую очередь, прежде чем искать баги в логике.

2.    Отлаживайте по частям. Запуск всего скрипта целиком при ошибке — это лотерея. Проверяйте каждую команду отдельно в терминале.

3.    Цветной вывод — это не украшение, это удобство. С ANSI-кодами сразу видно, где красное, а где зелёное.

4.    Выносите повторяющийся код в функции. Функция send_to_telegram используется везде поменять её в одном месте гораздо лучше, чем в десяти.

5.    Тихие ошибки самые коварные. Всегда проверяйте, что происходит, когда команда возвращает не то, что вы ожидаете.

В итоге получился инструмент, который реально работает и реально используется. Без тяжёлых зависимостей, на чистом bash, на любом Linux-сервере.

Но главное это не скрипт. Главное то, что путь от «да тут всё просто» до работающего решения всегда длиннее, чем кажется. И это нормально. Так устроена любая реальная работа в отличие от инструкции, где всё с первого раза.

Применяйте на своих серверах. Они заслуживают присмотра.

https://github.com/ku78/system-monitor-scripts

ссылка на оригинал статьи https://habr.com/ru/articles/1044276/