Логи и ошибки


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



Вводные данные

Заявки заказчику идут от нескольких систем (тильда, марквиз и инвбокс), принимаются в его системе, обрабатываются (вебхуком) и затем перенаправляются дальше в крм. CRM забирает их через FTP (новый способ) и получает по электронной почте (старый способ). Внезапно оказалось, что часть заявок куда-то пропадает, как минимум две – они отправлены из сторонней системы, но по фтп не забрались. Надо разобраться в чем дело.

Начинаем разбираться. К счастью, на хостинге включено логирование апача – как доступа, так и ошибок за последнюю неделю. Заказчик дает сразу время и сайт (601), с которого приходили заявки, так что сначала точно удостоверяемся, что был пост-запрос (а то мало ли, может его просто не было и ищем отсутствующую черную кошку в темной комнате).

Поиск в файле access_log выдает такую строку:

81.212.213.211 - - [24/Jun/2022:23:07:17 +0300] "POST /envybox/app.php?parthner=601 HTTP/1.0" 200 787 "-" "-"
Да, все верно в 23 часа инвбокс отправлял вебхук и получил ответ 200 размером 787 байт. Текста ответа, к сожалению, нет, поэтому будем надеяться, что вышла какая-то ошибка и сохранилась в логах. Так что теперь смотрим, есть ли что-то в тоже время в файле error_log. И находим:

[Fri Jun 24 23:07:17 2022] [error] [pid 14110] sapi_apache2.c(362): [client 81.212.213.211:45390] PHP Fatal error:  Uncaught Error: Class 'PHPMailer\\PHPMailer\\Exception' not found in public_html/envybox/PHPMailer.php:1983\nStack trace:\n#0 public_html/envybox/PHPMailer.php(1797): PHPMailer\\PHPMailer\\PHPMailer->smtpConnect(Array)\n#1 public_html/envybox/PHPMailer.php(1539): PHPMailer\\PHPMailer\\PHPMailer->smtpSend('Date: Fri, 24 J...', 'This is a multi...')\n#2 public_html/envybox/PHPMailer.php(1375): PHPMailer\\PHPMailer\\PHPMailer->postSend()\n#3 public_html/envybox/app.php(338): PHPMailer\\PHPMailer\\PHPMailer->send()\n#4 {main}\n  thrown in public_html/envybox/PHPMailer.php on line 1983
Отлично, ошибку мы нашли. В этом виноват стары метод, который отправляет письма, а не записывает файлы в директорию для последующего забора по фтп. Судя по логу тут две ошибки – не найден класс PHPMailer для обработки ошибок и содержимое письма не текст/хтмл, а какое-то мульти – может посчитало картинкой или еще что.

Исправление ошибок

В данном случае идем в код файла app.php и закомментируем все, что относится к формированию письма и последующей его отправке. Также сразу копируем в папку файл Exception.php для PHPMailer – мало ли захочем снова включить отправку, чтобы скрипт не прерывался.

Дальше ставим свои логи для получения и сохранения содержимого запроса. Это просто – создаем табличку, реализуем запись в базу данных, например метод insertLog и пишем все

$temp_data = file_get_contents('php://input');
insertLog($temp_data);
Потом в любой момент времени, если снова возникнут ошибки, можно будет посмотреть, что именно передают нам инвбокс или марквиз. Также можно настроить очистку этой таблицы по расписанию, опционально.

Также давайте посмотрим на код, его немного, может еще увидим тонкие моменты. И находим сразу – вставка значений в базу данных. Реализуется онапримерно так:

$query = "INSERT INTO `table ` (`id`, `komm1`) VALUES ('$zid', '$data');";
$ress = (mysqli_query($conn, $query) or die (mysqli_error($conn)));
В переменной $data может же быть абсолютно любая текстовая информация. Например, одиночные кавычки - и вставка в бд не выполнится. Так что добавим вот такую строку

$data = $conn->real_escape_string($data);
Теперь запрос пройдет. Также можно еще добавить обработку ошибки в бд – но это уже опционально, заказчик не просил нас делать всего, просто решить текущую проблему, а там уже будет видно.

Вот так проходить типичный поиск проблемы – логи и просмотр кода. Это один, пожалуй, самый простой пример, иногда проблема плавающая, её невозможно воспроизвести и решение приходит через месяцы, зачастую – совершенно случайно. Особенно это касается сложных систем, над которыми до вас работали десятки людей.
Автор этого материала - я - Пахолков Юрий. Я оказываю услуги по написанию программ на языках Java, C++, C# (а также консультирую по ним) и созданию сайтов. Работаю с сайтами на CMS OpenCart, WordPress, ModX и самописными. Кроме этого, работаю напрямую с JavaScript, PHP, CSS, HTML - то есть могу доработать ваш сайт или помочь с веб-программированием. Пишите сюда.

тегизаметки, ошибки, сайтостроение, php




Отправляя сообщение я подтверждаю, что ознакомлен и согласен с политикой конфиденциальности данного сайта.




Состояния потоков и планирование их выполнения
Коллекции Java: введение
Джо Хилл "Коробка в форме сердца"