Сообщить об ошибке.

Принцип работы пакета logging в Python

Как работает пакет logging

В этом разделе рассмотрен принцип работы и связь основных элементов в процесса регистрации событий пакета logging

Объекты Logger - регистраторы.

Объекты логгера выполняют тройную работу:

  1. Объекты регистратора предоставляют несколько методов коду приложения, чтобы приложения могли регистрировать сообщения во время выполнения.
  2. Объекты журнала определяют, на какие сообщения журнала регистрировать, основываясь на уровне логирования или фильтрах.
  3. Объекты регистратора передают соответствующие сообщения журнала всем заинтересованным обработчикам журнала.

Наиболее широко используемые методы для объектов регистратора делятся на две категории: настройка и отправка сообщений.

Наиболее распространенные методы настройки:

  • Метод Logger.setLevel() указывает самый низкий уровень логирования событий, которые будет обрабатывать регистратор. Уровень DEBUG - это самый низкий уровень встроенной важности, а CRITICAL - самая высокая встроенная серьезность. Например, если уровень логирования равен INFO, то регистратор будет обрабатывать только сообщения INFO, WARNING, ERROR и CRITICAL и будет игнорировать сообщения DEBUG.
  • Метод Logger.addHandler() и Logger.removeHandler() добавляют и удаляют объекты-обработчики из объекта регистратора.
  • Метод Logger.addFilter() и Logger.removeFilter() добавляют и удаляют объекты фильтра из объекта регистратора.

Не нужно вызывать эти методы для каждого созданного вами регистратора.

Методы ведения журнала:

  • Методы Logger.debug(), Logger.info(), Logger.warning(), Logger.error() и Logger.critical() создают записи журнала с сообщением и уровнем, соответствующим их названиям. Передаваемое в методы сообщение на самом деле является строкой формата, которая может содержать стандартный синтаксис подстановки строк %s, %d, %f и т. д. Остальные аргументы - это список объектов, которые соответствуют полям подстановки в сообщении. Что касается **kwargs, методы ведения журнала заботятся только о ключевом слове exc_info и используют его, чтобы определить, регистрировать ли информацию об исключениях.
  • Метод Logger.exception() создает сообщение журнала, подобное Logger.error(). Разница в том, что Logger.exception() создает и прикрепляет к сообщению дамп стека исключения. Вызывайте этот метод только из обработчика исключений.
  • Метод Logger.log() принимает дополнительный аргумент уровня логирования журнала. Это немного многословно для регистрации сообщений, чем методы перечисленных выше. Этот метод может пригодится, если пользователь регистрирует свои уровни логирования журнала.

Функция logging.getLogger() возвращает ссылку на экземпляр регистратора с именем, если оно указано, или root, если нет. Имена представляют собой иерархические структуры, разделенные точками. Многократные вызовы logging.getLogger() с одним и тем же именем возвращают ссылку на один и тот же объект logger. Регистраторы, которые находятся ниже в иерархическом списке, являются потомками регистраторов, которые находятся выше в списке. Например, при наличии регистратора с именем foo, регистраторы с именами foo.bar, foo.bar.baz и foo.bam являются потомками foo.

У регистраторов есть концепция эффективного уровня. Если уровень логирования регистратора явно не задан Logger.setLevel(), то вместо него используется уровень его родителя. Если родитель не имеет явного установленного уровня логирования, то используется уровень его родителя, и так далее - ищутся все предки, пока не будет найден явно установленный уровень. В корневом объекте Logger всегда установлен явный уровень, равный по умолчанию WARNING. Для принятия решения о передачи сообщения дальше обработчикам, используется найденный эффективный уровень логирования.

Дочерние регистраторы распространяют сообщения вплоть до обработчиков, связанных с их регистраторами-предками. Из-за этого нет необходимости определять и настраивать обработчики для всех регистраторов, которые использует приложение. Достаточно настроить обработчики для регистратора верхнего уровня и создать дочерние регистраторы по мере необходимости. Можно отключить распространение, установив для атрибута регистратора propagate значение False.)

Объекты-обработчики Handler.

Объекты-обработчики Handler отвечают за отправку соответствующих сообщений журнала, в зависимости от уровня логирования, в указанное место назначения обработчика. Объекты регистратора Logger могут добавлять к себе ноль или более объектов-обработчиков с помощью метода Logger.addHandler(). В качестве примера сценария приложение может захотеть отправлять все сообщения журнала в файл журнала, сообщения ERROR или выше в стандартный вывод, а сообщения CRITICAL на адрес электронной почты. Этот сценарий требует трех отдельных обработчиков, где каждый обработчик отвечает за отправку сообщений определенной важности в определенное место.

В обработчике очень мало методов для разработчиков приложений. Можно выделить актуальные методы для пользователей, которые использующих встроенные объекты-обработчики, то есть не создающие пользовательские обработчики:

  • Метод Handler.setLevel(), как и в объектах регистратора, определяет наименьший уровень логирования, который будет отправлен в ​​соответствующее место назначения. Почему существует два метода .setLevel() у регистратора и обработчика? Уровень логирования, установленный в объекте Logger, используется для передачи соответствующих событий обработчикам. Уровень логирования, установленный в каждом обработчике Handler, определяет, на какие события ему стоит реагировать.
  • Метод Handler.SetFormatter() выбирает объект Formatter для использования этим обработчиком.
  • Методы Handler.addFilter() и removeFilter() соответственно настраивают и удаляют объекты фильтра на обработчиках.

Код приложения не должен напрямую создавать и использовать экземпляры Handler. Класс Handler является базовым классом, который определяет интерфейс, который должны иметь все обработчики и устанавливает поведение по умолчанию, которое дочерние классы могут использовать или переопределять.

Объекты форматирования Formatter.

Объекты форматирования Formatter настраивают окончательный порядок, структуру и содержимое сообщения журнала. В отличие от базового класса logging.Handler, код приложения может создавать экземпляры классов форматирования. Если приложению требуется специальное поведение, то можно создать свой подкласс Formatter. Конструктор класса принимает три необязательных аргумента - строку формата сообщения fmt, строку формата даты datefmt и индикатор стиля style.

logging.Formatter.__init__(fmt=None, datefmt=None, style='%')

Если строка формата сообщения fmt отсутствует, по умолчанию используется необработанное сообщение. Если строка формата даты отсутствует, то формат даты по умолчанию имеет вид %Y-%m-%d %H:%M:%S, с прикрепленными в конце миллисекундами.

Стиль style является одним из '%', ‘{‘ или ‘$’. Если ни один из них не указан, то будет использоваться '%'.

Если стиль '%', то строка формата сообщения fmt использует подстановку строки в стиле %(<dictionary key>)s. Возможные ключи документированы в атрибутах LogRecord. Если стиль равен '{', то предполагается, что строка формата сообщения совместима с str.format() с использованием ключевых аргументов, в то время как если стиль '$', совместима с string.Template.substitute().

Следующая строка формата сообщения будет регистрировать время в удобочитаемом формате, уровень логирования сообщения и содержимое сообщения в указанном порядке:

'%(asctime)s - %(levelname)s - %(message)s'

Объекты форматирования Formatter используют настраиваемую пользователем функцию для преобразования времени создания записи в кортеж. По умолчанию используется time.localtime(). Чтобы изменить ее для конкретного экземпляра Formatter, необходимо установить для атрибута converter функцию с той же сигнатурой, что и time.localtime() или time.gmtime(). Чтобы изменить его для всех Formatter, то установите атрибут converter в классе Formatter.