PSR-3 читать на русском -- протоколирование и логгирование

Данный документ описывает общий интерфейс библиотек протоколирования.

Основная цель данного документа – позволить библиотекам получать объект Psr\Log\LoggerInterface и использовать его простым и универсальным образом для реализации протоколирования. В случае, если некий фреймворк или CMS нуждается в расширенном функционале, МОЖНО расширять данный интерфейс, но СЛЕДУЕТ сохранять совместимость с описанными в данном документе правилами. Это позволит сторонним библиотекам, применяемым при разработке приложения, использовать централизованную систему протоколирования.

Слова «НЕОБХОДИМО» / «ДОЛЖНО» ("MUST"), «НЕДОПУСТИМО» ("MUST NOT"), «ТРЕБУЕТСЯ» ("REQUIRED"), «НУЖНО» ("SHALL"), «НЕ ПОЗВОЛЯЕТСЯ» ("SHALL NOT"), «СЛЕДУЕТ» ("SHOULD"), «НЕ СЛЕДУЕТ» ("SHOULD NOT"), «РЕКОМЕНДУЕТСЯ» ("RECOMMENDED"), «МОЖЕТ» / «ВОЗМОЖНО» ("MAY") и «НЕОБЯЗАТЕЛЬНО» ("OPTIONAL") в этом документе следует понимать так, как это описано в RFC 2119 (и его переводе).

Слово «разработчик» (implementor) в данном документе следует понимать как «автор, реализующий интерфейс LoggerInterface в неких библиотеке или фреймворке, связанных с протоколированием». Пользователи систем протоколирования упоминаются как просто «пользователи».

1. Спецификации

1.1 Основы

Интерфейс LoggerInterface предоставляет восемь методов протоколирования, соответствующих восьми уровням протоколирования, описанным в RFC 5424 (отладка (debug), информация (info), замечание (notice), предупреждение (warning), ошибка (error), критическая ошибка (critical), тревога (alert), авария (emergency)).

Девятый метод, «протокол» (log) принимает в качестве первого аргумента уровень протоколирования. Вызов этого метода с передачей константы одного из уровней протоколирования ДОЛЖЕН приводить к тому же результату, что и вызов соответствующего переданному уровню протоколирования специального метода.

Вызов этого метода с передачей уровня протоколирования, не описанного в данной спецификации, ДОЛЖЕН приводить к порождению исключения Psr\Log\InvalidArgumentException в случае, если конкретная реализация системы протоколирования не поддерживает переданный уровень протоколирования.

Пользователям НЕ СЛЕДУЕТ использовать собственные уровни протоколирования без полной уверенности в том, что конкретная реализация системы протоколирования их поддерживает.

1.2 Сообщения

  • Каждый метод протоколирования должен принимать строку-сообщение или объект с методом __toString(). Разработчики МОГУТ использовать специальные обработчики переданных объектов, но если этого не сделано, объект ДОЛЖЕН быть приведён к строке.
  • Строка-сообщение МОЖЕТ содержать плейсхолдеры, которые МОГУТ быть заменены на конкретные значения из массива context.
  • Имена плейсхолдеров ДОЛЖНЫ совпадать со значениями ключей массива context.
  • Плейсхолдеры ДОЛЖНЫ быть заключены в одиночные фигурные скобки, при этом НЕ ДОЛЖНО быть пробелов между фигурными скобками и именем плейсхолдера.
  • Имена плейсхолдеров НУЖНО составлять только из символов A-Z, a-z, 0-9/span
  • Разработчики МОГУТ реализовывать со значениями плейсхолдеров различные стратегии экранирования и преобразования при отображении протокола. Пользователям НЕ НУЖНО предварительно экранировать данные в значениях плейсхолдеров, т.к. заранее не известно, как и в каком контексте содержащаяся в них информация может быть использована.

Ниже для ознакомления представлен пример обработки плейсхолдеров:

<?php
/**
    * Подстановка значений в плейсхолдеры сообщения.
    */
    function interpolate($message, array $context = array())
    {
      // Построение массива подстановки с фигурными скобками
      // вокруг значений ключей массива context.
      $replace = array();
      foreach ($context as $key => $val) {
          $replace['{' . $key . '}'] = $val;
      }
 
      // Подстановка значений в сообщение и возврат результата.
      return strtr($message, $replace);
    }
 
    // Сообщение с плейсхолдером, имя которого обрамлено
    // фигурными скобками.
    $message = "User {username} created";
 
    // Массив context с данными для замены плейсхолдера на
    // итоговое значение.
    $context = array('username' => 'bolivar');
 
    // Результат: "User bolivar created"
    echo interpolate($message, $context);

1.3 Контекст

  • Каждый метод получает массив сопутствующих данных (context), содержащих дополнительную информацию, представление которой в виде строки не является оптимальным. На содержимое массива не налагается никаких ограничений. Разработчики ДОЛЖНЫ обрабатывать данные массива context максимально гибко. Переданные в массиве context данные НЕ ДОЛЖНЫ порождать исключений, вызывать сообщений об ошибках, предупреждений или замечаний от интерпретатора PHP.
  • Если в массив context передан объект исключения, он ДОЛЖЕН находиться в элементе с ключом 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 будет
 * заменено на значение элемента массива context с ключом "foo".
 *
 * Массив context может содержать произвольные данные. Единственное
 * предположение, допустимое для разработчиков, заключается в том, что
 * если в массиве переда объект исключения для построения трассировки
 * стека, он ДОЛЖЕН находиться в элементе массива с ключом "exception".
 *
 * См. полную спецификацию интерфейса здесь: https://github.com/php-fig/fig-standards...
 */
interface LoggerInterface
{
    /**
     * Авария, система неработоспособна.
     *
     * @param строка $message
     * @param массив $context
     * @return null
     */
    public function emergency($message, array $context = array());
 
    /**
     * Тревога, меры должны быть предприняты незамедлительно.
     *
     * Примеры: весь веб-сайт недоступен, БД недоступна и т.д. Вплоть до
     * отправки SMS-сообщения ответственному лицу.
     *
     * @param строка $message
     * @param массив $context
     * @return null
     */
    public function alert($message, array $context = array());
 
    /**
     * Критическая ошибка, критическая ситуация.
     *
     * Пример: недоступен компонент приложения, неожиданное исключение.
     *
     * @param строка $message
     * @param массив $context
     * @return null
     */
    public function critical($message, array $context = array());
 
    /**
     * Ошибка на стадии выполнения, не требующая неотложного вмешательства,
     * но требующая протоколирования и дальнейшего изучения.
     *
     * @param строка $message
     * @param массив $context
     * @return null
     */
    public function error($message, array $context = array());
 
    /**
     * Предупреждение, нештатная ситуация, не являющаяся ошибкой.
     *
     * Пример: использование устаревшего API, неверное использование API,
     * нежелательные эффекты и ситуации, которые, тем не менее,
     * не обязательно являются ошибочными.
     *
     * @param строка $message
     * @param массив $context
     * @return null
     */
    public function warning($message, array $context = array());
 
    /**
     * Замечание, важное событие.
     *
     * @param строка $message
     * @param массив $context
     * @return null
     */
    public function notice($message, array $context = array());
 
    /**
     * Информация, полезные для понимания происходящего события.
     *
     * Пример: авторизация пользователя, протокол взаимодействия с БД.
     *
     * @param строка $message
     * @param массив $context
     * @return null
     */
    public function info($message, array $context = array());
 
    /**
     * Детальная отладочная информация.
     *
     * @param строка $message
     * @param массив $context
     * @return null
     */
    public function debug($message, array $context = array());
 
    /**
     * Протоколирование с произвольным уровнем.
     *
     * @param смешанный $level
     * @param строка $message
     * @param массив $context
     * @return null
     */
    public function log($level, $message, array $context = array());
}

4. Интерфейс Psr\Log\LoggerAwareInterface

<?php
 
namespace Psr\Log;
 
/**
 * Описывает систему, поддерживающую протоколирование.
 */
interface LoggerAwareInterface
{
    /**
     * Устанавливает объект протоколирования в объект
     * системы, поддерживающей протоколирование.
     *
     * @param LoggerInterface $logger
     * @return null
     */
    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';
}


Источники: