В этом разделе рассмотрен принцип работы и связь основных элементов в процесса регистрации событий пакета logging
Logger
- регистраторы.Объекты логгера выполняют тройную работу:
Наиболее широко используемые методы для объектов регистратора делятся на две категории: настройка и отправка сообщений.
Наиболее распространенные методы настройки:
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
.