Ваше приложение молчит — это плохой знак
Вы когда-нибудь узнавали о баге на продакшене от разгневанного пользователя? Если да — вы знаете, как это больно. Если нет — вам повезло (пока).
PHP — язык, который работает на 78% всех сайтов мира. Но у него есть одна особенность: он слишком «тихий». По умолчанию PHP просто проглотит ошибку, покажет белую страницу или, что ещё хуже, продолжит работать с неверными данными. Без системы мониторинга и логирования вы слепы.
В этой статье мы разберём, как превратить ваше PHP-приложение из «чёрного ящика» в прозрачную систему, где каждая ошибка, каждый медленный запрос и каждое подозрительное действие будут зафиксированы. Поехали!
Почему «echo $error» — это не логирование?
Многие начинающие разработчики пишут:
try {
// какой-то код
} catch (Exception $e) {
echo $e->getMessage();
}
Это не логирование. Это крик в пустоту. Вывод в браузер не сохраняется, не структурируется и не даёт вам никакой аналитики. Настоящее логирование — это когда вы можете:
- Увидеть ошибку через 5 минут после её возникновения
- Понять, на каком сервере и в каком окружении это произошло
- Отфильтровать тысячи записей и найти ту самую
- Получить уведомление в Telegram/Slack, если что-то сломалось
Давайте перейдём к инструментам, которые это умеют.
Monolog — стандарт де-факто для PHP
Если вы пишете на PHP и не используете Monolog, вы, скорее всего, изобретаете велосипед. Это библиотека, которая стала стандартом для логирования в PHP (да, Laravel и Symfony используют её под капотом).
Установка и простейший пример
composer require monolog/monolog
<?php
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
// Создаём канал логов
$log = new Logger('my_app');
// Пишем в файл /var/log/my_app.log
$log->pushHandler(new StreamHandler('/var/log/my_app.log', Logger::WARNING));
// Используем
$log->warning('Это предупреждение');
$log->error('Критическая ошибка: база данных недоступна');
Уже лучше. Но Monolog умеет гораздо больше. Вы можете отправлять логи в разные места одновременно:
- В файл — для локальной отладки
- В Elasticsearch — для полноценного поиска
- В Telegram/Slack — для срочных уведомлений
- В Syslog — для системного администрирования
Продвинутый пример с несколькими обработчиками
<?php
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\TelegramBotHandler;
use Monolog\Handler\ElasticsearchHandler;
use Monolog\Formatter\LineFormatter;
$log = new Logger('production');
// Все ошибки пишем в файл
$fileHandler = new StreamHandler('/var/log/app.log', Logger::DEBUG);
$log->pushHandler($fileHandler);
// Критические ошибки — сразу в Telegram
$telegramHandler = new TelegramBotHandler(
'YOUR_BOT_TOKEN',
'YOUR_CHAT_ID',
Logger::CRITICAL
);
$telegramHandler->setFormatter(new LineFormatter(
"[%datetime%] %channel%.%level_name%: %message% %context%\n"
));
$log->pushHandler($telegramHandler);
// Логируем
$log->critical('База данных упала', ['server' => gethostname()]);
Теперь, если база упадёт ночью, вы узнаете об этом по уведомлению в телефоне. А не утром от клиента.
Sentry — мониторинг ошибок с контекстом
Monolog отлично пишет логи, но когда ошибок становится много, просто читать файлы — это ад. Тут на помощь приходит Sentry — система сбора ошибок с веб-интерфейсом.
Sentry автоматически собирает:
- Стек вызовов (stack trace)
- Данные запроса (URL, заголовки, тело)
- Информацию о пользователе (если передали)
- Состояние переменных в момент ошибки
- Количество повторений (чтобы понять, насколько проблема массовая)
Подключение Sentry в PHP
composer require sentry/sdk
<?php
use Sentry\SentrySdk;
use Sentry\State\Hub;
use Sentry\ClientBuilder;
SentrySdk::init()->bindClient(
ClientBuilder::create(['dsn' => 'https://your-dsn@sentry.io/1234567'])->getClient()
);
// Пример: логируем исключение
try {
throw new \RuntimeException('Что-то пошло не так');
} catch (\Throwable $e) {
\Sentry\captureException($e);
}
// Или просто сообщение
\Sentry\captureMessage('Пользователь загрузил странный файл');
После этого все ошибки улетают в Sentry, где их можно группировать, назначать ответственных и просматривать статистику. Бесплатный план покрывает до 5 тысяч событий в месяц — для небольшого проекта хватает за глаза.
ELK-стек: когда логов много
Если ваше приложение обрабатывает миллионы запросов, файлы логов становятся бесполезными. Вы просто не сможете в них найти нужную строчку. Тут нужен ELK-стек (Elasticsearch, Logstash, Kibana).
Схема работы:
- PHP-приложение пишет логи в JSON-формате в файл или напрямую в Logstash
- Logstash собирает, парсит и отправляет в Elasticsearch
- Kibana визуализирует данные: графики, дашборды, поиск
Пример: отправка логов в Elasticsearch через Monolog
<?php
use Monolog\Logger;
use Monolog\Handler\ElasticsearchHandler;
use Elastic\Elasticsearch\ClientBuilder;
$client = ClientBuilder::create()
->setHosts(['localhost:9200'])
->build();
$log = new Logger('app');
$esHandler = new ElasticsearchHandler($client, [
'index' => 'php-logs-' . date('Y-m-d'),
'type' => '_doc'
]);
$log->pushHandler($esHandler);
$log->info('Пользователь залогинился', [
'user_id' => 42,
'ip' => $_SERVER['REMOTE_ADDR']
]);
Теперь вы можете в Kibana построить график «ошибки по часам» или найти все логи конкретного пользователя за секунду.
Мониторинг производительности: Xdebug и Blackfire
Логирование ошибок — это полдела. Но что делать, если приложение просто тормозит? Тут нужен профилировщик.
Xdebug — бесплатно и сердито
Включите профилирование в php.ini:
xdebug.mode = profile
xdebug.output_dir