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

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

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

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

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

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

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

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

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

#!/bin/bash

TG_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 ;;
    esac
done

Установка

# Создаём файл скрипта
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

Комментарии (3)


  1. MEGA_Nexus
    06.06.2026 06:12

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

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

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

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

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

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


    1. JBFW
      06.06.2026 06:12

      Вот есть например у вас свой небольшой любимый сервер (или большой, но он занимается какими-то своими задачами, и совать туда лишнее не стоит).

      А контролировать иногда надо. И вот вместо того, чтобы ставить туда какую-то "систему мониторинга" с вероятными зависимостями и сайд-эффектами - гораздо проще добавить маленький скрипт, который покажет то, что вы хотите, и так, как вы хотите.


  1. JBFW
    06.06.2026 06:12

    Если у вас шелл-скрипт глючит непонятно почему - попробуйте запустить его с ключиком -x

    sh -x script

    Или вообще в заголовке добавьте.

    Тогда оно будет выполняться и писать на экране что именно и когда делается.