Общий интерфейс логирования
Этот документ описывает общий интерфейс для библиотек логирования.
Основная цель — позволить библиотекам получать объект Psr\Log\LoggerInterface
и
записывать в него логи простым и универсальным способом.
Фреймворки и CMS, которые имеют индивидуальные потребности,
МОГУТ реализовывать интерфейс для своих собственных целей,
но ДОЛЖНЫ оставаться совместимыми с ним.
Это гарантирует, что сторонние библиотеки, которые использует приложение,
могут записывать в централизованный лог этого приложения.
Ключевые слова «ДОЛЖЕН», «НЕ ДОЛЖЕН», «ТРЕБУЕТСЯ», «СЛЕДУЕТ», "НЕ ДОЛЖЕН", "РЕКОМЕНДУЕТСЯ", "МОЖЕТ" и "ДОПОЛНИТЕЛЬНО" в этом документе должны быть интерпретированы, как описано в RFC 2119.
Слово разработчик
в этом документе должно интерпретироваться как кто-то, кто реализует интерфейс
LoggerInterface
в сторонней библиотеке или фреймворке.
Пользователи, которые используют логгер, называются словом пользователь
.
1. Спецификация
1.1 Основы
-
Интерфейс
LoggerInterface
предоставляет восемь методов для записи логов в восемь RFC 5424 уровней (debug (отладка), info (информация), notice (уведомление), warning (предупреждение), error ( ошибка), critical (критическая ошибка), alert (предупреждение), emergency (чрезвычайная ситуация)). -
Девятый метод,
log
, принимает уровень журнала в качестве первого аргумента. Вызов этого метода с одной из констант уровня журнала ДОЛЖЕН иметь тот же результат, что и вызов специфичного для уровня метода. Вызов этого метода с уровнем, который не определен в этой спецификации, ДОЛЖЕН генерировать исключениеPsr\Log\InvalidArgumentException
если реализация не знает об этом уровне. Пользователи НЕ ДОЛЖНЫ использовать пользовательский уровень, не зная наверняка, что текущая реализация поддерживает этот уровень.
1.2 Сообщение
- Каждый метод принимает в качестве сообщения строку или объект с реализованным методом
__toString()
. -
Разработчики МОГУТ реализовывать специальную обработку переданного объекта. Если это не так, разработчики ДОЛЖНЫ преобразовать его в строку.
-
Сообщение МОЖЕТ содержать заполнители, которые разработчики МОГУТ заменить на значения из контекстного массива.
-
Имена плейсхолдеров ДОЛЖНЫ соответствовать ключам в контекстном массиве.
-
Имена плейсхолдеров ДОЛЖНЫ быть разделены одной открывающей фигурной скобкой
{
и одной закрывающей фигурной скобкой}
. НЕ ДОЛЖНО быть пробела между разделителями и именем плейсхолдера. -
Имена плейсхолдеров ДОЛЖНЫ состоять только из символов
A-Z
,a-z
,0-9
, символа подчеркивания_
и точки.
. Использование других символов зарезервировано для будущих модификаций спецификации плейсхолдеров. -
Разработчики МОГУТ использовать плейсхолдеры для реализации различных стратегий экранирования и отображения логов. Пользователям НЕ СЛЕДУЕТ предварительно экранировать значения плейсхолдеров, так как они могут не знать в каком контексте будут отображаться данные.
-
Ниже приведен пример реализации плейсхолдера. Только для справки:
<?php
/**
* Преобразование контекстных значений в значения плейсхолдера
*/
function interpolate($message, array $context = array())
{
// Создаем замещающий массив с фигурными скобками вокруг контекстных ключей
$replace = array();
foreach ($context as $key => $val) {
// проверяем, что значение может быть приведено к строке
if (!is_array($val) && (!is_object($val) || method_exists($val, '__toString'))) {
$replace['{' . $key . '}'] = $val;
}
}
// заменяем и возвращаем результат
return strtr($message, $replace);
}
// сообщение с плейсхолдером
$message = "User {username} created";
// массив для замены
$context = array('username' => 'bolivar');
// выводит "User bolivar created"
echo interpolate($message, $context);
1.3 Контекст
-
Каждый метод принимает массив в качестве данных контекста. Это сделано для того, чтобы можно было бы передавать данные, которые невозможно представить в виде строки. Массив может содержать что угодно. Разработчики ДОЛЖНЫ гарантировать, что они обрабатывают данные контекста не строго. Заданное значение в контексте НЕ ДОЛЖНО бросать исключение и не должно вызывает никаких ошибок, предупреждений или уведомлений.
-
Если объект
Exception
передается в данных контекста, он ДОЛЖЕН быть помещен в ключexception
. Регистрация исключений является распространенным шаблоном. Это позволяет разработчикам получать трассировку стека из исключения, если это возможно. Разработчики ДОЛЖНЫ по-прежнему проверять, что значение ключаexception
на самом деле является исключением (Exception
), прежде чем использовать его как таковой, поскольку он МОЖЕТ содержать что-либо еще.
1.4 Вспомогательные классы и интерфейсы
-
Класс
Psr\Log\AbstractLogger
позволяет вам реализоватьLoggerInterface
очень легко, расширив его и реализовав общий методlog
. Остальные восемь методов пересылают ему сообщение и контекст. -
Аналогично, использование
Psr\Log\LoggerTrait
требует от вас только реализовать общий методlog
. Обратите внимание, что, поскольку трейты не могут реализовывать интерфейсы, в этом случае вам все равно придется реализовать интерфейсLoggerInterface
. -
Класс
Psr\Log\NullLogger
предоставляется вместе с интерфейсом. Он МОЖЕТ использоваться разработчиками для реализации резервной «черной дыры», если им не предоставлен регистратор. Однако условная регистрация может быть лучшим подходом, если создание контекстных данных неприменимо. -
Класс
Psr\Log\LoggerAwareInterface
содержит только методsetLogger(LoggerInterface $logger)
и может использоваться фреймворками для автоматического связывания произвольных экземпляров с регистратором. -
Трейт
Psr\Log\LoggerAwareTrait
можно использовать для простой реализации аналогичного интерфейса в любом классе. Такая реализация дает вам доступ к$this->logger
. -
Класс
Psr\Log\LogLevel
содержит константы для восьми уровней логирования.
2. Пакет
Описанные интерфейсы и классы, а также соответствующие классы исключений и набор тестов для проверки вашей реализации предоставляются как часть psr/log пакета.
3. Psr\Log\LoggerInterface
<?php
namespace Psr\Log;
/**
* Описывает общий интерфейс логирования
*
* Сообщение ДОЛЖНО быть строкой или объектом, реализующим __toString().
*
* Сообщение МОЖЕТ содержать плейсхолдеры в форме: {foo}, где foo
* будут заменены данными контекста из ключа "foo".
*
* Контекстный массив может содержать произвольные данные, единственное предположение,
* которое могут сделать разработчики, заключается в том, что если экземпляр Exception дается
* для создания трассировки стека, он ДОЛЖЕН находиться в ключе «exception».
*
*/
interface LoggerInterface
{
/**
* Чрезвычайная ситуация. Система непригодна для использования.
*
* @param string $message
* @param array $context
* @return void
*/
public function emergency($message, array $context = array());
/**
* Действия должны быть приняты немедленно.
*
* Пример: весь веб-сайт недоступен, база данных недоступна и т. д. Это должно вызвать SMS-уведомления и разбудить вас.
*
* @param string $message
* @param array $context
* @return void
*/
public function alert($message, array $context = array());
/**
* Критические условия.
*
* Пример: компонент приложения недоступен, неожиданное исключение.
*
* @param string $message
* @param array $context
* @return void
*/
public function critical($message, array $context = array());
/**
* Ошибки времени выполнения, которые не требуют немедленных действий, но обычно должны регистрироваться и отслеживаться.
*
* @param string $message
* @param array $context
* @return void
*/
public function error($message, array $context = array());
/**
* Исключительные случаи, не являющиеся ошибками.
*
* Пример: использование устаревших API, неправильное использование API, нежелательные вещи, которые не обязательно являются неправильными.
*
* @param string $message
* @param array $context
* @return void
*/
public function warning($message, array $context = array());
/**
* Обычные, но важные события.
*
* @param string $message
* @param array $context
* @return void
*/
public function notice($message, array $context = array());
/**
* Интересные события.
*
* Пример: вход пользователя в систему, запись лога SQL.
*
* @param string $message
* @param array $context
* @return void
*/
public function info($message, array $context = array());
/**
* Подробная отладочная информация.
*
* @param string $message
* @param array $context
* @return void
*/
public function debug($message, array $context = array());
/**
* Логирование с заданным уровнем.
*
* @param mixed $level
* @param string $message
* @param array $context
* @return void
*/
public function log($level, $message, array $context = array());
}
4. Psr\Log\LoggerAwareInterface
<?php
namespace Psr\Log;
/**
* Описывает экземпляр с поддержкой ведения лога.
*/
interface LoggerAwareInterface
{
/**
* Устанавливает экземпляр лога для объекта.
*
* @param LoggerInterface $logger
* @return void
*/
public function setLogger(LoggerInterface $logger);
}
5. Psr\Log\LogLevel
<?php
namespace Psr\Log;
/**
* Описывает уровни логирования
*/
class LogLevel
{
const EMERGENCY = 'emergency';
const ALERT = 'alert';
const CRITICAL = 'critical';
const ERROR = 'error';
const WARNING = 'warning';
const NOTICE = 'notice';
const INFO = 'info';
const DEBUG = 'debug';
}