Введение: Зачем нужно логирование в PHP?
Логирование — это не просто запись ошибок в файл. Это ваш главный инструмент для мониторинга, отладки и анализа работы веб-приложения. Без качественного логирования вы будете гадать, почему сайт упал или почему пользователь не может оформить заказ. Для начинающих разработчиков на PHP настройка правильного логирования — это первый шаг к профессиональной разработке.
Представьте, что ваше приложение — это черный ящик. Логи — это единственный способ заглянуть внутрь, понять, что происходит в каждый момент времени. В этой статье мы разберем лучшие практики, которые помогут вам избежать типичных ошибок новичков и построить надежную систему мониторинга.
1. Основы: встроенные функции PHP для логирования
PHP предоставляет несколько встроенных функций для работы с логами. Самая простая и популярная — error_log(). Она позволяет отправить сообщение в системный лог сервера или в указанный файл.
Базовый пример использования error_log()
// Простейшая запись ошибки в системный лог
error_log("Это сообщение об ошибке", 0);
// Запись в конкретный файл
error_log("Ошибка подключения к базе данных", 3, "/var/log/php_errors.log");
// Запись с указанием типа сообщения
error_log("Предупреждение: медленный запрос", 4);
Однако использовать error_log() напрямую в продакшене — не лучшая идея. Во-первых, вы смешиваете разные типы сообщений. Во-вторых, сложно управлять форматом и ротацией логов. Для серьезных проектов лучше использовать специализированные библиотеки.
Настройка php.ini для улучшенного логирования
Перед тем как писать код, убедитесь, что ваш php.ini настроен правильно:
; Включаем логирование ошибок
log_errors = On
; Путь к файлу лога
error_log = /var/log/php_errors.log
; Максимальный размер лога (в байтах)
log_errors_max_len = 1024
; Отключаем вывод ошибок на экран (для продакшена)
display_errors = Off
; Включаем логирование всех уровней ошибок
error_reporting = E_ALL
2. Уровни логирования: от DEBUG до CRITICAL
Одна из главных ошибок новичков — записывать все сообщения в одну кучу. Профессиональное логирование использует уровни серьезности. Это помогает быстро фильтровать логи и не пропускать критические ошибки среди информационных сообщений.
Стандартные уровни PSR-3
PHP-сообщество приняло стандарт PSR-3, который определяет 8 уровней логирования:
- DEBUG — детальная отладочная информация (используется только в разработке)
- INFO — информационные сообщения (пользователь зарегистрировался, заказ создан)
- NOTICE — нормальные, но значимые события (использование устаревших функций)
- WARNING — предупреждения (например, медленный запрос, низкий запас места)
- ERROR — ошибки, требующие внимания (не удалось подключиться к БД)
- CRITICAL — критические ошибки (основной компонент системы недоступен)
- ALERT — требует немедленного вмешательства (взлом, отказ системы)
- EMERGENCY — система неработоспособна
Пример реализации уровней с Monolog
Лучшая библиотека для логирования в PHP — Monolog. Она полностью соответствует PSR-3 и легко настраивается:
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\RotatingFileHandler;
use Monolog\Level;
// Создаем логгер с именем канала
$log = new Logger('app');
// Добавляем обработчик для всех уровней
$log->pushHandler(new StreamHandler('/var/log/app.log', Level::Debug));
// Отдельный файл для критических ошибок
$log->pushHandler(
new RotatingFileHandler('/var/log/critical.log', 30, Level::Critical)
);
// Использование
$log->info('Пользователь вошел в систему', ['user_id' => 123]);
$log->error('Ошибка подключения к БД', ['db' => 'main', 'error' => 'timeout']);
$log->critical('Сервер базы данных недоступен');
3. Структурированное логирование: добавляем контекст
Простые текстовые сообщения — это прошлый век. Современное логирование должно быть структурированным. Вместо строки "Ошибка в заказе" вы должны записывать JSON с ID заказа, пользователем, временем и стеком вызовов.
Почему это важно?
- Быстрый поиск — вы можете найти все ошибки по конкретному пользователю
- Агрегация — системы вроде ELK (Elasticsearch, Logstash, Kibana) отлично работают с JSON
- Автоматизация — можно настроить алерты на определенные паттерны
Пример структурированного лога
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Formatter\JsonFormatter;
$log = new Logger('payment');
$handler = new StreamHandler('/var/log/payments.log');
$handler->setFormatter(new JsonFormatter());
$log->pushHandler($handler);
// Запись с контекстом
$log->error('Платеж отклонен', [
'user_id' => 456,
'order_id' => 7890,
'amount' => 1500.00,
'payment_method' => 'card',
'error_code' => 'INSUFFICIENT_FUNDS',
'ip_address' => '192.168.1.1',
'timestamp' => date('c')
]);
// Результат в файле будет выглядеть так:
// {"message":"Платеж отклонен","context":{"user_id":456,...},"level":400,"level_name":"ERROR","channel":"payment","datetime":"2024-01-15T10:30:00+00:00"}
4. Лучшие практики и частые ошибки
Что делать НУЖНО:
- Используйте ротацию логов — файлы не должны расти бесконечно. Monolog поддерживает
RotatingFileHandler