СоХабр закрыт.

С 13.05.2019 изменения постов больше не отслеживаются, и новые посты не сохраняются.

| сохранено

H Мониторинг доступности сервера или сайта с применением PHP в черновиках

Применения PHP для целей системного администрирования редкая вещь, но для решения простых задач — это вполне допустимо. На Хабре данная тематика освещена слабо. Но возможно представить ситуацию, когда у человека есть знания PHP и его основная работа не дает времени изучить что-то другое, например, Python или Perl. Вот для такой категории людей может пригодится эта статья.

Предлагаемый скрипт дает возможность пинговать серверы и получать код состояния HTTP. Соответственно можно оперативно узнать время выхода сайта из строя или отсутствие доступности какого-то сервера для ping. Оповещение приходит на email и СМС. Решение с почтой вряд ли вызовет вопросы, чего не скажешь об отправке СМС. Реализация отправки сообщений на телефон организована с помощью услуг сайта sms.ru. Данный сервис предоставляет до 60 бесплатных СМС программистам для своих разработок. Вам потребуется зарегистрироваться на сайте и в разделе «Программистам» взять готовый PHP-пример для отправки сообщений на свой телефон. Он будет выглядеть примерно так:
$body=file_get_contents("http://sms.ru/sms/send?api_id=505dfad707-a5df30-aa04jkhkjhk-02f507654e7c&to=380950000000&text=".urlencode(iconv("windows-1251","utf-8","Привет!")));

Практически без изменений пример попадет в скрипт. В вашем варианте будет другой ID и номер телефона соответственно.

Скрипт мониторинга рассчитан для работы на Linux системе. Обратите внимание, чтобы выполнить скрипт в терминале указывая просто название, его потребуется сделать исполняемым командой chmod +x и в начало текста программы добавить #!/usr/bin/env php, что уже сделано в нашем случае. Иначе, имя скрипта в терминале придется предварять словом php. Также, удобно запускать скрипт с помощью cron каждые 30 минут. Для обкатки рекомендую запустить вначале в терминале, если будут ошибки они отобразятся на экране.

Для правильной работы на компьютере должны быть установлены и настроены: PHP, PHP-CLI, sendmail.

Вот собственно и текст скрипта:
Текст скрипта для мониторинга
#!/usr/bin/env php
<?php
//error_reporting(0);

// Устанавливаем временную зону. Пригодится для показа даты и времени в письме.

date_default_timezone_set('Europe/Kiev');

$hostToPing = @fopen(__DIR__."/hosts_to_ping", 'rb');

// Определяем переменную для вывода справки в терминал.

$help = "NULL";
for ($i = 0; $i < $argc; $i++)
{
    if ($argv[$i] == "-h") {
       $help = "-h"; 
    }       
}

/* Проверяем существование файла, если нет, выводим справку, его размер 
 * (если пустой, выводим справку), если аргументов больше одного, выводим справку, 
 * если указан аргумент -h, выводим справку.
 */

if ((!$hostToPing) || (filesize(__DIR__."/hosts_to_ping") == "0") || ($argc > 1) || ($help == "-h")) {
    echo <<<_END
    
/////////////////////////////////////////***Справка***//////////////////////////////////////////////////
    
    Скрипт на PHP для пинга и проверки http ответа сервера. Зависимости: PHP, PHP CLI, sendmail, ping. 
    В папке с программой должен находиться текстовый конфигурационный файл hosts_to_ping. В нем,
    первой строкой обязательно укажите email на который будут отсылаться уведомления. Далее
    в каждой новой строке (можно оставлять пустые строки) укажите имя сервера и через пробел 
    (табуляцию) тип проверки. Имя сервера указывается без http://, если это URL или указывайте IP. 
    Осуществляется два типа проверки ping и проверка ответа на http запрос. Во втором случае, если 
    ответ - 200, значит все ОК, если нет, то на почту будет отправлено соответствующее уведомление.
    Пример файла конфигурации:
    
        your_mail@domain.com
    
        site.com    http
        site.org    ping
        8.8.8.8     ping
        
////////////////////////////////////////////////////////////////////////////////////////////////////////\n

_END;
fclose($hostToPing);
exit();
}

/* Читаем первую строку, там должен быть e-mail, если не проходит проверку на @ 
 * выводим ошибку в терминал.
 */

$tomail = fgets($hostToPing);
$tomail = trim($tomail);
if (strpos("$tomail", "@") === false) {
    die("Указан неправильный e-mail!. Смотрите справку указав аргумент -h.\n");
}
$text_error_ping = "Нет ответа на ping.";
$text_error_http = "Ответ сервера:";

// Читаем со второй строки.

while (!feof($hostToPing)) {
    $stroka = fgets($hostToPing);
    
/* Ищем пустые строки. Убираем все пробельные символы и смотрим длину строки, 
 * если 0, то она пустая, пропускаем итерацию цикла.   
 */
    
    $test = preg_replace('/\s/', "", $stroka);   
    if (strlen($test) == "0") {        
        continue;
    }

// Убираем пробелы вначале и в конце строки.
    
    $stroka = trim($stroka);

// Меняем все табы и где больше одного пробела на один пробел.
    
    $stroka = preg_replace('/\s+/', " ", $stroka);
    
// Делим строку по пробелу.
    
    $opcii = explode(" ", $stroka);    

// Выбираем тип проверки, проверяем, если ошибка отсылаем на мыло  и телефон.
    
    if ($opcii[1] == "http") {
        $URL = "http://".$opcii[0];
            if (!get_headers($URL)){
                sendMailError($URL, "Нет ответа на http запрос. Возможно сервер не пингуется!", $tomail);
                sendSMS($URL.": Ошибка http! Возможно сервер не пингуется!");
            }
            else {
                $otvet = get_headers($URL);
                if (substr($otvet[0], 9, 3) != "200") {
                    $text_error_http = $text_error_http." ".substr($otvet[0], 9, 3);
                    sendMailError($URL, $text_error_http, $tomail);                    
                    sendSMS($URL." ".$text_error_http);
                }                
            }
    }   
    elseif ($opcii[1] == "ping") {
        $command = 'ping -c 10'." ".$opcii[0]." 2> /dev/null 1>&2";
        system($command, $return_var);       
        if ($return_var != "0") {
            sendMailError($opcii[0], $text_error_ping, $tomail);
            sendSMS($opcii[0].": ".$text_error_ping);
        }       
    }

 // Отсылаем ошибку на мыло и телефон, если указан неправильный аргумент
    
    elseif ($opcii[1] != "ping" && $opcii[1] != "http") {
        sendMailError($opcii[0], "Указаны неправильные настройки в конфигурационном файле! Смотрите справку указав аргумент -h.", $tomail);
        sendSMS($opcii[0].": неправильная настройка в конфиге!");
    }    
}
fclose($hostToPing);

// Функция отправки сообщения на mail.

function sendMailError($nameServer, $text, $toaddress) {
    $date_m = date('l jS \of F Y h:i:s A');    
    $mailcontent = "
<html>
<head>
    <title>Что-то произошло! Отчет о состоянии серверов</title>
</head>
<body>
    <div style=\"width: 800px; background-color: olive; color: white; border: 1px dotted graytext; text-align: center; text-transform: uppercase;\">
        <h3>Что-то произошло! Отчет о состоянии серверов</h3>
    </div>
    <div style=\"width: 800px; background-color: saddlebrown; color: white; border: 1px dotted graytext;\">
        <h3><b>Сервер:</b> $nameServer</h3>
        <h3><b>Сообщение:</b></h3>
        <p>$text</p>            
        <p>$date_m</p>
    </div>
</body>
</html>";
    
    $subject = "Что-то произошло! Отчет о состоянии серверов.";
    $headers  = 'MIME-Version: 1.0' . "\r\n";
    $headers .= 'Content-type: text/html; charset=UTF-8' . "\r\n";
    $headers .= "From: admin@helper". "\r\n";
    
    mail($toaddress, $subject, $mailcontent, $headers);    
}

function sendSMS($textSMS) {
    $body=file_get_contents("http://sms.ru/sms/send?api_id=505adfdd707-adf0-aa04-99b9dkfkj7654e7c&to=380950000000&text="
            .urlencode("$textSMS"));
}
?>


Конечно, кто-то спросит: «Зачем это все?». Я назову несколько аргументов: бесплатно, просто и полезно. Ведь есть интернет-сервисы с аналогичным базовым функционалом и при этом, услуги предоставляются за деньги. На этом все.

комментарии (14)

+2
nobilix ,   * (был изменён)
Ох, вы смелый! И код API sms.ru и номер телефона выложили (скорее всего не свой)
Которые, к слову, стоит тоже вынести в конфиг, наверное, а не хардкодить в скрипте
0
zelenin ,  
судя по jkhkjhk в api_id — невалидный
0
+1 –1
Filosof8 ,  
Уже не валидный))). Пару смсок, видимо от пользователя nobilix я получил)))
0
nobilix ,  
не обессудьте )) я не мог не проверить)
0
Filosof8 ,  
ID меняется одним щелчком мыши. Поэтому проблемы никакой нет.
+1
Kudja ,  
SMS излишне для меня в этом случае, но в целом
1. uptimerobot.com — здесь мониторинг скриптов, бесплатно
2. Если нужно СМС уведомление — как вариант привязываем аккаунт к почте на mail.ru к спец. ящику, а у него выставляем уведомление по СМС о письмах…

Кстати именно второй пункт использую в случае, когда надо мониторить в срочном порядке какие-то вещи — делаю уведомление на такое мыло и соответственно вижу СМС-ку если что-то не так.
0
+1 –1
Blumfontein ,  
1) Guzzle, Swiftmailer и GetOpt вам в помощь.
2) Почему такой странный формат кофигурационного файла? Почему не return array();?
3) По алгоритму, можно было бы сделать и поумнее. Если 1 раз запрос с сайта не пришел, это еще не значит, что он недоступен. Может временная проблема с сеткой. Я бы сделал так (цифры указаны только для примера):
а) Делаем раз в час запрос на сайт
б) Если ответ 200, все ок
в) Если не 200, то в течение 2 минут делаем еще 2 запроса
г) Если хоть 1 из них 200, то все ок.
д) Если не 200, то пингуем.
е) Не пингуется => шлем письмо «Сервер не пингуется, пинай сисадмина»
ж) Если пингуется, пробуем зайти по SSH
з) Не заходит => шлем письмо «Зайти по SSH не удалось, пинай сисадмина»
и) Если заходит, вытаскиваем логи apache/nginx/whatever, шлем письмо и прикладываем логи туда.
к) Как опцию, можно добавить перезагрузку MySQL/nginx/server/whatever => далее шаг 1
0
Filosof8 ,  
Насчет перезагрузки «MySQL/nginx/server/whatever » отличная идея!
+1
kotomyava ,  
Ничего нет отличного, в идее автоматически перегружать сервис, по какой-то причине упавший, не выяснив до этого причину.
–2
Filosof8 ,  
Но ведь есть логи. А сервис должен быть доступен конечным пользователям постоянно!
0
kotomyava ,  
С немалой вероятностью он и не станет доступен. Мало того, ситуация после перезагрузки может только усугубиться, особенно если это тот же MySQL — можно спровоцировать и потерю данных.
К тому же, логи не панацея, и далеко не всегда по ним можно всё узнать, и понять что происходило.
А чтобы сервис был доступен, да, нужен мониторинг, и своевременное вмешательство специалиста, если возникает проблема. И перезагрузка сервиса его отнюдь не заменяет.
0
casuss ,   * (был изменён)
По п.3 — поддерживаю, плюс проблема с сеткой может быть и у проверяющего сервера.
Как вариант с СМС — сервис mail2SMS у некоторых операторов еще работает. И проверка сайта может производится силами скромного Bash-скрипта по Cron. Что-то типа:
check=`wget $url -O - |grep -с "строка, что должна быть на странице, лучше в конце" `
if [ $check == "0" ]  then  "тут код отправки мыла на номер mail2SMS" fi 

wget и grep — по вкусу.
«код отправки» — дополнить по вкусу действиями по аварийному поднятию сервера, как выше предлагалось.
0
Filosof8 ,  
Можно, но у баша меньше возможностей. Если скрипт расширить и усложнить, например, по списку Blumfontein, баш уже не справится. Можно выполнять запросы с помощью PHP CURL, на сайте sms.ru есть пример с использованием этой опции, а также пример с усиленной безопасностью. Это стартовый вариант, дальше можно усложнять…
0
bezumkin ,  

Я, наверное, чего-то не понимаю, но чем автора не устроила та же Яндекс.Метрика?