Эффективное логирование в PHP: библиотеки и техники

Раздел: Разработка и администрирование PHP -> Настройка и использование логирования

Эффективное логирование PHP с Monolog

Наиболее распространенное и гибкое решение для логирования в PHP - библиотека Monolog. Она позволяет отправлять логи в различные каналы (файлы, базы данных, email, системные журналы) с разными уровнями серьезности.

Как настроить Monolog для записи логов в файл?

Установка через Composer:

composer require monolog/monolog

Ru log php (логирование php на русском)

Пример базовой настройки:

use Monolog\Logger;
use Monolog\Handler\StreamHandler;

$log = new Logger('my_app');
$log->pushHandler(new StreamHandler('/var/log/php/app.log', Logger::WARNING));

$log->warning('Это предупреждение');
$log->error('Произошла ошибка');

В данном примере создается логгер с именем канала 'my_app', добавляется обработчик, который пишет в файл /var/log/php/app.log все записи уровня WARNING и выше.

Типичные проблемы:

  • Файл лога не создается или не доступен для записи - проверьте права на директорию и файл.
  • Логи не отображаются - возможно, уровень логирования слишком высокий (например, DEBUG не будет записан, если обработчик настроен на WARNING).
  • Кодировка файла - рекомендуется указывать encoding в StreamHandler.

Как использовать встроенную функцию error_log?

PHP предоставляет функцию error_log для записи сообщений в журнал ошибок сервера или в указанный файл.

error_log('Текст ошибки', 3, '/tmp/php_errors.log');

Второй параметр - тип сообщения: 0 (отправляется в системный журнал), 1 (по email), 3 (в файл). Третий параметр - путь к файлу.

Проблемы: Нет гибкости в форматировании, нельзя указать уровень, сложно ротировать логи.

Как настроить пользовательский обработчик ошибок с set_error_handler?

Для перехвата всех ошибок PHP (кроме фатальных) можно установить свою функцию.

function customError($severity, $message, $file, $line) {
    $log = date('Y-m-d H:i:s') . \" [\" . $severity . \"] \" . $message . \" in \" . $file . \":\" . $line . \"\\n\";
    file_put_contents('/var/log/php/errors.log', $log, FILE_APPEND);
}
set_error_handler('customError');

// Вызов несуществующей функции
trigger_error('Тестовая ошибка', E_USER_WARNING);

Этот способ позволяет контролировать формат записи и обрабатывать ошибки произвольно.

Проблема: Фатальные ошибки (E_ERROR, E_PARSE) не перехватываются. Для них требуется register_shutdown_function.

Как логировать исключения с set_exception_handler?
function exceptionHandler($exception) {
    file_put_contents('/var/log/php/exceptions.log',
        '[' . date('Y-m-d H:i:s') . '] ' . $exception->getMessage() . \"\\n\",
        FILE_APPEND);
}
set_exception_handler('exceptionHandler');

throw new \Exception('Тестовое исключение');
Как объединить Monolog с обработчиками ошибок PHP?

Можно интегрировать Monolog с set_error_handler и set_exception_handler, чтобы все ошибки и исключения записывались через единую систему.

$log = new Logger('app');
$log->pushHandler(new StreamHandler('/var/log/php/errors.log', Logger::ERROR));

set_error_handler(function($severity, $message, $file, $line) use ($log) {
    $log->error($message, ['file' => $file, 'line' => $line]);
});

set_exception_handler(function($exception) use ($log) {
    $log->critical($exception->getMessage(), ['trace' => $exception->getTraceAsString()]);
});

Такой подход дает единый формат и возможность добавлять контекст.

Расширенные примеры логирования

Пример
// Пример 1: Monolog с ротацией и форматтером
use Monolog\Logger;
use Monolog\Handler\RotatingFileHandler;
use Monolog\Formatter\LineFormatter;

$log = new Logger('app');
$handler = new RotatingFileHandler('/var/log/php/app.log', 30, Logger::DEBUG);
$handler->setFormatter(new LineFormatter(\"[%datetime%] %channel%.%level_name%: %message% %context% %extra%\\n\"));
$log->pushHandler($handler);

$log->info('Информационное сообщение', ['user_id' => 123]);
[2023-10-01 12:00:00] app.INFO: Информационное сообщение {"user_id":123} []
Пример
// Пример 2: Логирование в syslog через SyslogHandler
use Monolog\Handler\SyslogHandler;
$syslogHandler = new SyslogHandler('myapp', LOG_USER, Logger::ERROR);
$log->pushHandler($syslogHandler);
$log->error('Критическая ошибка');
Пример
// Пример 3: Пользовательский обработчик ошибок с Monolog
function errorToMonolog($severity, $message, $file, $line) {
    global $log;
    $log->error($message, ['file' => $file, 'line' => $line]);
}
set_error_handler('errorToMonolog');

// Теперь все ошибки будут записываться через Monolog в файл с ротацией
Пример
// Пример 4: Логирование в базу данных (PDO)
use Monolog\Logger;
use Monolog\Handler\PDOHandler;
$pdo = new PDO('mysql:host=localhost;dbname=logs', 'user', 'pass');
$handler = new PDOHandler($pdo, 'log_table', Logger::WARNING);
$log = new Logger('db');
$log->pushHandler($handler);
$log->warning('Сообщение в БД');
Пример
// Пример 5: Добавление контекста через IntrospectionProcessor
use Monolog\Processor\IntrospectionProcessor;
$log->pushProcessor(new IntrospectionProcessor(Logger::DEBUG, ['skipClassesPartials' => ['Monolog\\']]));
$log->info('Где я?');
extra: {\"file\":\"/var/www/html/index.php\",\"line\":42,\"class\":\"App\\Controller\\IndexController\",\"function\":\"index\"}
Пример
// Пример 6: Группировка каналов с GroupHandler
use Monolog\Handler\GroupHandler;
$fileHandler = new StreamHandler('/var/log/php/app.log', Logger::INFO);
$syslogHandler = new SyslogHandler('myapp', LOG_USER, Logger::ERROR);
$group = new GroupHandler([$fileHandler, $syslogHandler]);
$log = new Logger('multi');
$log->pushHandler($group);
$log->info('Сообщение в файл');
$log->error('Ошибка в файл и syslog');
Пример
// Пример 7: Использование BufferHandler для накопления и пакетной записи
use Monolog\Handler\BufferHandler;
$buffer = new BufferHandler($fileHandler, 10, Logger::DEBUG);
$log->pushHandler($buffer);
for ($i = 0; $i < 5; $i++) {
    $log->info('Буферизованное сообщение ' . $i);
}
// При разрушении логгера или принудительном flush данные будут записаны
Пример
// Пример 8: Логирование с использованием PSR-3 интерфейса (через абстракцию)
use Psr\Log\LoggerInterface;
use Monolog\Logger;

class MyService {
    public function __construct(private LoggerInterface $logger) {}
    public function doSomething() {
        $this->logger->info('Сервис выполнен');
    }
}

$monolog = new Logger('service');
$monolog->pushHandler(new StreamHandler('/var/log/php/service.log', Logger::INFO));
$service = new MyService($monolog);
$service->doSomething();

Логирование PHP на русском - comments

En
Ru log php (php)