Что такое Monolog и зачем он нужен?
Monolog — это стандартная библиотека для логирования в PHP. Она предоставляет гибкий и мощный инструментарий для записи логов в различные каналы (файлы, базы данных, электронную почту, системный журнал, внешние сервисы и т.д.). Monolog является де-факто стандартом для PHP-приложений, особенно в экосистеме Symfony, Laravel и других современных фреймворков.
Зачем нужна эта библиотека? В любом приложении необходимо отслеживать события: ошибки, предупреждения, информационные сообщения, отладочную информацию. Monolog позволяет:
- Централизовать логирование — писать логи в одном формате и из любого места приложения.
- Гибко настраивать каналы — отправлять критические ошибки в Telegram/Slack, а информационные сообщения — в файл.
- Форматировать сообщения — добавлять дату, уровень, контекст, стек вызовов.
- Фильтровать логи — обрабатывать только сообщения определённого уровня.
- Интегрироваться с фреймворками — в Symfony, Laravel, Yii2 используется именно Monolog.
Установка
Monolog устанавливается через Composer — стандартный менеджер пакетов для PHP.
composer require monolog/monolog
Если вы используете PHP 8.0+, рекомендуется устанавливать последнюю стабильную версию. После установки в проекте появится папка vendor и файл composer.json с зависимостью.
Быстрый старт
Самый простой пример — запись лога в файл:
<?php
require 'vendor/autoload.php';
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
// Создаём логгер с именем канала 'my_app'
$log = new Logger('my_app');
// Добавляем обработчик — запись в файл
$log->pushHandler(new StreamHandler('app.log', Logger::WARNING));
// Теперь можно логировать
$log->warning('Это предупреждение');
$log->error('Это ошибка');
echo "Логи записаны в app.log";
?>
После выполнения скрипта в файле app.log появится что-то вроде:
[2025-04-09T10:30:00.123456+00:00] my_app.WARNING: Это предупреждение [] []
[2025-04-09T10:30:00.123789+00:00] my_app.ERROR: Это ошибка [] []
Основные методы и функции
Рассмотрим ключевые методы Monolog. Все они являются частью класса Monolog\Logger или связанных классов.
1. pushHandler(HandlerInterface $handler)
Что делает: Добавляет обработчик (handler) в стек. Логгер может иметь несколько обработчиков, и каждый из них будет получать все сообщения (если не настроена фильтрация).
Параметры:
$handler— объект, реализующийMonolog\Handler\HandlerInterface(например,StreamHandler,FirePHPHandler,SlackHandler).
Пример:
$log = new Logger('app');
$log->pushHandler(new StreamHandler('debug.log', Logger::DEBUG));
$log->pushHandler(new StreamHandler('errors.log', Logger::ERROR));
// Теперь сообщения уровня ERROR и выше попадут в оба файла
2. addRecord(int $level, string $message, array $context = [])
Что делает: Базовый метод для записи лога. Обычно не вызывается напрямую, вместо него используются методы-обёртки (debug(), info() и т.д.).
Параметры:
$level— уровень логирования (константы:Logger::DEBUG,Logger::INFO,Logger::WARNINGи т.д.).$message— текст сообщения.$context— массив дополнительных данных (например, ID пользователя, IP-адрес).
Пример:
$log->addRecord(Logger::INFO, 'Пользователь вошёл в систему', ['user_id' => 42]);
3. debug(string $message, array $context = [])
Что делает: Записывает отладочное сообщение (уровень DEBUG — 100). Используется для детальной информации, полезной при разработке.
Параметры: те же, что и у addRecord.
Пример:
$log->debug('SQL запрос выполнен за {time} ms', ['time' => 12.5]);
4. info(string $message, array $context = [])
Что делает: Записывает информационное сообщение (уровень INFO — 200). Обычно используется для отслеживания нормального хода работы приложения.
Пример:
$log->info('Крон-задача выполнена успешно', ['task' => 'send_emails']);
5. warning(string $message, array $context = [])
Что делает: Записывает предупреждение (уровень WARNING — 300). Указывает на потенциальную проблему, которая не является критической.
Пример:
$log->warning('Диск заполнен на 90%', ['disk_usage' => 90]);
6. error(string $message, array $context = [])
Что делает: Записывает ошибку (уровень ERROR — 400). Приложение продолжает работу, но произошёл сбой.
Пример:
$log->error('Не удалось подключиться к БД', ['db_host' => 'localhost', 'error' => $e->getMessage()]);
7. critical(string $message, array $context = [])
Что делает: Записывает критическую ошибку (уровень CRITICAL — 500). Приложение может быть частично недоступно.
Пример:
$log->critical('Исчерпан лимит памяти', ['memory_limit' => ini_get('memory_limit')]);
8. alert(string $message, array $context = [])
Что делает: Записывает тревожное сообщение (уровень ALERT — 550). Требуется немедленное вмешательство администратора.
Пример:
$log->alert('Сервер атакован!', ['ip' => '192.168.1.1', 'attempts' => 1000]);
9. emergency(string $message, array $context = [])
Что делает: Самый высокий уровень (EMERGENCY — 600). Система полностью неработоспособна.
Пример:
$log->emergency('Полный отказ системы', ['uptime' => 0]);
10. pushProcessor(callable $processor)
Что делает: Добавляет процессор — функцию, которая модифицирует запись лога перед отправкой обработчикам. Например, можно автоматически добавлять IP-адрес или ID сессии.
Параметры:
$processor— callable, принимающий массив записи лога и возвращающий его.
Пример:
$log->pushProcessor(function ($record) {
$record['extra']['ip'] = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
return $record;
});
$log->info('Тест'); // В логе появится extra.ip
11. popHandler()
Что делает: Удаляет последний добавленный обработчик из стека.
Пример:
$log->pushHandler(new StreamHandler('temp.log'));
$log->info('Сообщение уйдёт в temp.log');
$log->popHandler(); // Удаляем обработчик
$log->info('Это сообщение уже никуда не попадёт');
Реальный практический пример использования
Рассмотрим полноценный пример — логирование действий пользователя в веб-приложении с отправкой критических ошибок в Telegram.
<?php
require 'vendor/autoload.php';
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\TelegramBotHandler;
use Monolog\Processor\IntrospectionProcessor;
// Создаём логгер
$logger = new Logger('user_actions');
// 1. Обработчик для записи всех логов в файл
$fileHandler = new StreamHandler(__DIR__ . '/logs/app.log', Logger::DEBUG);
$logger->pushHandler($fileHandler);
// 2. Обработчик для отправки критических ошибок в Telegram
$telegramHandler = new TelegramBotHandler(
'YOUR_BOT_TOKEN', // Токен бота
'YOUR_CHAT_ID', // ID чата
Logger::CRITICAL // Только CRITICAL и выше
);
$logger->pushHandler($telegramHandler);
// 3. Добавляем процессор для включения стека вызовов
$logger->pushProcessor(new IntrospectionProcessor());
// Симуляция действий пользователя
function processOrder($orderId, $logger) {
try {
// Логируем начало обработки
$logger->info('Начало обработки заказа', ['order_id' => $orderId]);
// Имитация ошибки
if ($orderId <= 0) {
throw new \InvalidArgumentException('Некорректный ID заказа');
}
// Успешное завершение
$logger->info('Заказ обработан', ['order_id' => $orderId]);
} catch (\Exception $e) {
// Критическая ошибка — уйдёт и в файл, и в Telegram
$logger->critical('Ошибка обработки заказа', [
'order_id' => $orderId,
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString()
]);
}
}
processOrder(123, $logger);
processOrder(-1, $logger);
echo "Логирование завершено. Проверьте logs/app.log и Telegram.";
?>
В этом примере:
- Все сообщения пишутся в файл
app.log. - Сообщения уровня
CRITICALи выше дополнительно отправляются в Telegram. - Добавлен процессор
IntrospectionProcessor, который добавляет информацию о файле и строке, откуда был вызван логгер.
Советы и типичные ошибки
Советы:
- Используйте разные каналы — создавайте отдельные логгеры для разных частей приложения (например,
database,auth,payment). Это упрощает анализ. - Настраивайте уровни логирования — на продакшене не пишите DEBUG-логи в файл, иначе он быстро переполнится. Используйте
Logger::WARNINGили выше. - Используйте контекст — передавайте в
$contextмаксимум полезной информации (ID пользователя, IP, URL). Это сильно помогает при отладке. - Ротация логов — используйте
RotatingFileHandlerдля автоматической ротации файлов логов по дням. - Не логируйте пароли и токены — это угроза безопасности. Если нужно, используйте процессоры для маскировки.
Типичные ошибки:
- Забыли вызвать
pushHandler— без обработчика лог