Перейти к содержимому

16.6. logging – Средство журналирования для Python

Исходный код: Lib/logging/__init__.py


Этот модуль определяет функции и классы, реализующие гибкую систему журналирования событий для приложений и библиотек.

Ключевое преимущество наличия API журналирования в модуле стандартной библиотеки заключается в том, что все модули Python могут участвовать в журналировании, поэтому журнал вашего приложения может включать ваши собственные сообщения, объединенные с сообщениями от сторонних модулей.

Модуль предоставляет множество функций и гибкости. Если вы не знакомы с журналированием, лучший способ разобраться – изучить учебные пособия (см. ссылки справа).

Основные классы, определенные модулем, вместе с их функциями, перечислены ниже.

  • Регистраторы предоставляют интерфейс, который напрямую используется кодом приложения.

  • Обработчики отправляют записи журнала (созданные регистраторами) в соответствующее место назначения.

  • Фильтры предоставляют более детальное средство для определения того, какие записи журнала выводить.

  • Форматировщики определяют макет записей журнала в окончательном выводе.

16.6.1. Объекты Logger

Объекты Logger обладают следующими атрибутами и методами. Обратите внимание, что Logger'ы никогда не создаются напрямую, а всегда через функцию уровня модуля logging.getLogger(name). Многократные вызовы getLogger() с одним и тем же именем всегда возвращают ссылку на один и тот же объект Logger.

Значение name потенциально может быть иерархическим значением, разделённым точками, например foo.bar.baz (хотя это может быть и просто foo). Логгеры, расположенные ниже в иерархическом списке, являются дочерними по отношению к логгерам выше. Например, для логгера с именем foo логгеры с именами foo.bar, foo.bar.baz и foo.bam являются потомками foo. Иерархия имён логгеров аналогична иерархии пакетов Python и идентична ей, если вы организуете свои логгеры на основе модулей, используя рекомендуемую конструкцию logging.getLogger(__name__). Это потому, что в модуле __name__ – это имя модуля в пространстве имён пакетов Python.

classlogging.Logger
propagate

Если этот атрибут имеет значение true, события, записанные в этот логгер, будут передаваться обработчикам логгеров более высокого уровня (предков) в дополнение к любым обработчикам, прикреплённым к этому логгеру. Сообщения передаются напрямую обработчикам логгеров-предков – при этом ни уровень, ни фильтры этих логгеров-предков не учитываются.

Если это значение false, сообщения журнала не передаются обработчикам логгеров-предков.

Конструктор устанавливает этот атрибут в True.

Примечание

Если вы прикрепите обработчик к логгеру и к одному или нескольким его предкам, одна и та же запись может быть выдана несколько раз. В общем случае вам не следует прикреплять обработчик более чем к одному логгеру: если вы просто прикрепите его к подходящему логгеру, который находится наиболее высоко в иерархии логгеров, то он будет видеть все события, записанные всеми логгерами-потомками, при условии что их настройка propagate оставлена равной True. Типичный сценарий – прикреплять обработчики только к корневому логгеру и позволить распространению позаботиться обо всём остальном.

setLevel(level)

Устанавливает порог для этого логгера в level. Сообщения журнала, которые менее серьёзны, чем level, будут игнорироваться; сообщения журнала, имеющие серьёзность level или выше, будут выданы тем обработчиком (или обработчиками), который обслуживает этот логгер, если только уровень обработчика не был установлен на более высокий уровень серьёзности, чем level.

При создании логгера уровень устанавливается в NOTSET (что приводит к обработке всех сообщений, если логгер является корневым, или к делегированию родителю, если логгер не является корневым). Обратите внимание, что корневой логгер создаётся с уровнем WARNING.

Термин «делегирование родителю» означает, что если логгер имеет уровень NOTSET, то его цепочка логгеров-предков просматривается до тех пор, пока не будет найден предок с уровнем, отличным от NOTSET, или не будет достигнут корень.

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

Если достигнут корень и он имеет уровень NOTSET, то все сообщения будут обработаны. В противном случае уровень корня будет использоваться как эффективный уровень.

Список уровней приведён в разделе Logging Levels.

Изменено в версии 3.2: Параметр level теперь принимает строковое представление уровня, такое как 'INFO', в качестве альтернативы целочисленным константам, например INFO. Однако обратите внимание, что уровни внутри хранятся как целые числа, и методы, такие как getEffectiveLevel() и isEnabledFor(), будут возвращать/ожидать передачи целых чисел.

isEnabledFor(lvl)

Показывает, будет ли сообщение с уровнем важности lvl обработано этим регистратором. Этот метод сначала проверяет уровень, заданный на уровне модуля с помощью logging.disable(lvl), а затем эффективный уровень регистратора, определяемый функцией getEffectiveLevel().

getEffectiveLevel()

Указывает эффективный уровень для данного логгера. Если значение, отличное от NOTSET, было установлено с помощью setLevel(), оно и возвращается. В противном случае иерархия обходится в направлении корневого логгера, пока не будет найдено значение, отличное от NOTSET, и возвращается это значение. Возвращаемое значение является целым числом, обычно одним из logging.DEBUG, logging.INFO и т.д.

getChild(suffix)

Возвращает логгер, который является потомком данного логгера, определяемым по суффиксу. Таким образом, logging.getLogger('abc').getChild('def.ghi') вернёт тот же логгер, который был бы возвращён вызовом logging.getLogger('abc.def.ghi'). Это удобный метод, полезный, когда родительский логгер именуется, например, через __name__, а не с помощью строкового литерала.

Новое в версии 3.2.

debug(msg, *args, **kwargs)

Регистрирует сообщение с уровнем DEBUG в данном логгере. msg – это строка формата сообщения, а args – аргументы, которые объединяются с msg с помощью оператора форматирования строк. (Обратите внимание: это означает, что в строке формата можно использовать ключевые слова вместе с одним аргументом-словарём.)

В kwargs проверяются три ключевых аргумента: exc_info, stack_info и extra.

Если exc_info не является ложным, это приводит к добавлению информации об исключении в сообщение журнала. Если предоставлен кортеж исключения (в формате, возвращаемом sys.exc_info()) или экземпляр исключения, используется он; в противном случае вызывается sys.exc_info() для получения информации об исключении.

Второй необязательный именованный аргумент – stack_info, по умолчанию False. Если true, в сообщение журнала добавляется информация о стеке, включая сам вызов журналирования. Обратите внимание, что это не та же информация о стеке, что отображается при указании exc_info: первая – это фреймы стека от дна стека до вызова журналирования в текущем потоке, тогда как вторая – это информация о фреймах стека, которые были развёрнуты после исключения, при поиске обработчиков исключений.

Можно указать stack_info независимо от exc_info, например, чтобы просто показать, как был достигнут определённый участок кода, даже если никаких исключений не возникало. Фреймы стека выводятся после строки заголовка, которая гласит:

text
Stack (most recent call last):

Это имитирует Traceback (most recent call last):, который используется при отображении фреймов исключений.

Третий ключевой аргумент – extra, который можно использовать для передачи словаря. Этот словарь используется для заполнения __dict__ объекта LogRecord, созданного для события логирования, пользовательскими атрибутами. Затем эти настраиваемые атрибуты можно использовать по своему усмотрению. Например, их можно включать в записываемые сообщения. Например:

python
FORMAT = '%(asctime)-15s %(clientip)s %(user)-8s %(message)s'
logging.basicConfig(format=FORMAT)
d = {'clientip': '192.168.0.1', 'user': 'fbloggs'}
logger = logging.getLogger('tcpserver')
logger.warning('Protocol problem: %s', 'connection reset', extra=d)

выведет что-то вроде

text
2006-02-08 22:20:02,165 192.168.0.1 fbloggs  Protocol problem: connection reset

Ключи в словаре, передаваемом в extra, не должны совпадать с ключами, используемыми системой логирования. (См. документацию Formatter для получения дополнительной информации о том, какие ключи используются системой логирования.)

При использовании этих атрибутов в сообщениях необходимо соблюдать осторожность. В приведённом выше примере, например, Formatter настроен со строкой форматирования, которая ожидает атрибуты 'clientip' и 'user' в словаре атрибутов LogRecord. Если они отсутствуют, сообщение не будет зарегистрировано, так как возникнет исключение форматирования строки. Поэтому в данном случае необходимо всегда передавать словарь extra с этими ключами.

Хотя это может раздражать, данная возможность предназначена для использования в специализированных ситуациях, например, на многопоточных серверах, где один и тот же код выполняется во множестве контекстов, и возникающие интересные условия зависят от этого контекста (такие как IP-адрес удалённого клиента и имя аутентифицированного пользователя в приведённом выше примере). В таких обстоятельствах, скорее всего, будут использоваться специализированные Formatter с определёнными Handler.

Новое в версии 3.2: Добавлен параметр stack_info.

Изменено в версии 3.5: Параметр exc_info теперь может принимать экземпляры исключений.

info(msg, *args, **kwargs)

Записывает сообщение с уровнем INFO в этот логгер. Аргументы интерпретируются так же, как для debug().

warning(msg, *args, **kwargs)

Записывает сообщение с уровнем WARNING в этот логгер. Аргументы интерпретируются так же, как для debug().

Примечание

Существует устаревший метод warn, который функционально идентичен warning. Поскольку warn устарел, пожалуйста, не используйте его – используйте вместо него warning.

error(msg, *args, **kwargs)

Записывает сообщение с уровнем ERROR в этот логгер. Аргументы интерпретируются так же, как для debug().

critical(msg, *args, **kwargs)

Записывает сообщение с уровнем CRITICAL в этот логгер. Аргументы интерпретируются так же, как для debug().

log(lvl, msg, *args, **kwargs)

Регистрирует сообщение с целочисленным уровнем lvl в этом регистраторе. Остальные аргументы интерпретируются так же, как для debug().

exception(msg, *args, **kwargs)

Записывает сообщение с уровнем ERROR в этот логгер. Аргументы интерпретируются так же, как для debug(). Информация об исключении добавляется в сообщение. Этот метод следует вызывать только из обработчика исключений.

addFilter(filter)

Добавляет указанный фильтр filter в этот логгер.

removeFilter(filter)

Удаляет указанный фильтр filter из этого логгера.

filter(record)

Применяет фильтры этого регистратора к записи и возвращает true, если запись должна быть обработана. Фильтры опрашиваются по очереди, пока один из них не вернёт false. Если ни один не вернёт false, запись будет обработана (передана обработчикам). Если какой-либо возвращает false, дальнейшая обработка записи не производится.

addHandler(hdlr)

Добавляет указанный обработчик hdlr в этот логгер.

removeHandler(hdlr)

Удаляет указанный обработчик hdlr из этого логгера.

findCaller(stack_info=False)

Находит имя исходного файла и номер строки вызывающего кода. Возвращает имя файла, номер строки, имя функции и информацию о стеке в виде кортежа из 4 элементов. Информация о стеке возвращается как None, если только stack_info не равно True.

handle(record)

Обрабатывает запись, передавая её всем обработчикам, связанным с этим логгером и его родителями (пока не встретится ложное значение propagate). Этот метод используется для распакованных записей, полученных через сокет, а также для созданных локально. Фильтрация на уровне логгера применяется с помощью filter().

makeRecord(name, lvl, fn, lno, msg, args, exc_info, func=None, extra=None, sinfo=None)

Это фабричный метод, который можно переопределить в подклассах для создания специализированных экземпляров LogRecord.

hasHandlers()

Проверяет, настроены ли у этого логгера какие-либо обработчики. Для этого производится поиск обработчиков в этом логгере и его родителях в иерархии логгеров. Возвращает True, если обработчик найден, иначе False. Метод прекращает поиск вверх по иерархии, как только будет найден логгер, у которого атрибут 'propagate' установлен в false – это будет последний логгер, проверяемый на наличие обработчиков.

Новое в версии 3.2.

Изменено в версии 3.7: Теперь логгеры можно сериализовать и десериализовать.

16.6.2. Уровни журналирования

Числовые значения уровней логирования приведены в следующей таблице. Они нужны в первую очередь, если вы хотите определить собственные уровни и задать им определённые значения относительно предопределённых. Если определить уровень с тем же числовым значением, он перезапишет предопределённое значение; предопределённое имя будет потеряно.

Уровень

Числовое значение

CRITICAL

50

ERROR

40

WARNING

30

INFO

20

DEBUG

10

NOTSET

0

16.6.3. Объекты Handler

Обработчики имеют следующие атрибуты и методы. Обратите внимание: Handler никогда не создаётся напрямую; этот класс служит базой для более полезных подклассов. Однако метод __init__() в подклассах должен вызывать Handler.__init__().

classlogging.Handler
__init__(level=NOTSET)

Инициализирует экземпляр Handler, устанавливая его уровень, список фильтров в пустой список и создавая блокировку (с помощью createLock()) для сериализации доступа к механизму ввода-вывода.

createLock()

Инициализирует потоковую блокировку, которую можно использовать для синхронизации доступа к низкоуровневым функциям ввода-вывода, которые могут не быть потокобезопасными.

acquire()

Захватывает блокировку потока, созданную с помощью createLock().

release()

Освобождает блокировку потока, захваченную с помощью acquire().

setLevel(level)

Устанавливает порог для этого обработчика в level. Сообщения журнала, уровень серьёзности которых ниже level, будут игнорироваться. При создании обработчика уровень устанавливается в NOTSET (из-за чего обрабатываются все сообщения).

Список уровней приведён в разделе Logging Levels.

Изменено в версии 3.2: Параметр level теперь принимает строковое представление уровня, например 'INFO', вместо целочисленных констант, таких как INFO.

setFormatter(fmt)

Устанавливает Formatter для этого обработчика равным fmt.

addFilter(filter)

Добавляет указанный фильтр filter к этому обработчику.

removeFilter(filter)

Удаляет указанный фильтр filter из этого обработчика.

filter(record)

Применяет фильтры данного обработчика к записи и возвращает истинное значение, если запись должна быть обработана. Фильтры опрашиваются по очереди, пока один из них не вернёт ложное значение. Если ни один не вернул ложное значение, запись будет выдана. Если один возвращает ложное значение, обработчик не выдаст запись.

flush()

Гарантирует, что весь вывод журнала был сброшен. Эта версия ничего не делает и предназначена для реализации в подклассах.

close()

Освобождает все ресурсы, используемые обработчиком. Данная версия не выполняет вывод, но удаляет обработчик из внутреннего списка обработчиков, который закрывается при вызове shutdown(). Подклассы должны обеспечить вызов этого метода из переопределённых методов close().

handle(record)

Условно выдает указанную запись журнала в зависимости от фильтров, которые могли быть добавлены к обработчику. Оборачивает фактическую выдачу записи захватом/освобождением блокировки потока ввода-вывода.

handleError(record)

Этот метод должен вызываться из обработчиков, когда возникает исключение во время вызова emit(). Если атрибут уровня модуля raiseExceptions равен False, исключения молча игнорируются. Это в основном и нужно для системы журналирования – большинство пользователей не будут беспокоиться об ошибках в системе журналирования, их больше интересуют ошибки приложения. Однако вы можете заменить его на собственный обработчик, если пожелаете. Указанная запись – это та, которая обрабатывалась в момент возникновения исключения. (Значение по умолчанию raiseExceptionsTrue, так как это более полезно во время разработки.)

format(record)

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

emit(record)

Делает всё необходимое для фактической регистрации указанной записи журнала. Эта версия предназначена для реализации в подклассах и поэтому вызывает NotImplementedError.

Список стандартных обработчиков см. в logging.handlers.

16.6.4. Объекты Formatter

Объекты Formatter имеют следующие атрибуты и методы. Они отвечают за преобразование LogRecord (обычно) в строку, которая может быть интерпретирована человеком или внешней системой. Базовый Formatter позволяет указать строку форматирования. Если она не задана, используется значение по умолчанию '%(message)s', которое просто включает сообщение из вызова логирования. Чтобы добавить дополнительную информацию в форматированный вывод (например, временную метку), читайте дальше.

Форматировщик можно инициализировать строкой форматирования, которая использует знание об атрибутах LogRecord – например, упомянутое выше значение по умолчанию использует тот факт, что сообщение и аргументы пользователя предварительно форматируются в атрибут message объекта LogRecord. Эта строка форматирования содержит стандартные ключи подстановки в стиле % языка Python. См. раздел printf-style String Formatting для получения дополнительной информации о форматировании строк.

Полезные ключи подстановки в LogRecord приведены в разделе LogRecord attributes.

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

Возвращает новый экземпляр класса Formatter. Экземпляр инициализируется строкой форматирования для всего сообщения, а также строкой форматирования для части даты/времени сообщения. Если fmt не указан, используется '%(message)s'. Если datefmt не указан, используется формат, описанный в документации formatTime().

Параметр style может принимать значения '%', '{' или '$' и определяет, как\nстрока форматирования будет объединяться с данными: с помощью %-форматирования,\nstr.format() или string.Template. См. Использование определённых стилей форматирования во всём приложении\nдля получения дополнительной информации об использовании {}- и $-форматирования для сообщений журнала.

Изменено в версии 3.2: Добавлен параметр style.

format(record)

Словарь атрибутов записи используется как операнд операции форматирования строки. Возвращается результирующая строка. Перед форматированием словаря выполняется несколько подготовительных шагов. Атрибут message записи вычисляется с помощью msg % args. Если форматирующая строка содержит '(asctime)', то вызывается formatTime() для форматирования времени события. Если есть информация об исключении, она форматируется с помощью formatException() и добавляется к сообщению. Обратите внимание, что отформатированная информация об исключении кэшируется в атрибуте exc_text. Это полезно, поскольку информацию об исключении можно сериализовать и передавать по сети, но следует соблюдать осторожность, если имеется более одного подкласса Formatter, который настраивает форматирование информации об исключении. В этом случае необходимо очищать кэшированное значение после того, как форматер выполнит своё форматирование, чтобы следующий форматер, обрабатывающий событие, не использовал кэшированное значение, а пересчитывал его заново.

Если информация о стеке доступна, она добавляется после информации об исключении с использованием formatStack() для её преобразования при необходимости.

formatTime(record, datefmt=None)

Этот метод должен вызываться из format() форматером, который хочет использовать отформатированное время. Этот метод может быть переопределён в форматерах для любых конкретных требований, но основное поведение следующее: если указан datefmt (строка), он используется с time.strftime() для форматирования времени создания записи. В противном случае используется формат '%Y-%m-%d %H:%M:%S,uuu', где часть uuu – значение в миллисекундах, а остальные буквы – согласно документации time.strftime(). Пример времени в этом формате: 2003-01-23 00:29:50,411. Возвращается полученная строка.

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

Изменено в версии 3.3: Ранее формат по умолчанию был жёстко задан, как в этом примере: 2010-09-06 22:38:15,292, где часть до запятой обрабатывается строкой форматирования strptime ('%Y-%m-%d %H:%M:%S'), а часть после запятой – значение в миллисекундах. Поскольку в strptime нет плейсхолдера для миллисекунд, значение миллисекунд добавляется с помощью другой строки форматирования, '%s,%03d' – и обе эти строки форматирования были жёстко закодированы в этом методе. С этим изменением эти строки определяются как атрибуты уровня класса, которые при необходимости могут быть переопределены на уровне экземпляра. Имена атрибутов: default_time_format (для строки форматирования strptime) и default_msec_format (для добавления значения миллисекунд).

formatException(exc_info)

Форматирует указанную информацию об исключении (стандартный кортеж исключения, возвращаемый sys.exc_info()) в строку. Эта реализация по умолчанию просто использует traceback.print_exception(). Возвращается полученная строка.

formatStack(stack_info)

Форматирует указанную информацию о стеке (строку, возвращаемую traceback.print_stack(), но с удалённым последним символом новой строки) в строку. Эта реализация по умолчанию просто возвращает входное значение.

16.6.5. Объекты Filter

Filters может использоваться Handlers и Loggers для более сложной фильтрации, чем обеспечивается уровнями. Базовый класс фильтра пропускает только события, которые находятся ниже определённой точки в иерархии регистраторов. Например, фильтр, инициализированный строкой 'A.B', будет пропускать события, зарегистрированные регистраторами 'A.B', 'A.B.C', 'A.B.C.D', 'A.B.D' и т.д., но не 'A.BB', 'B.A.B' и т.д. Если инициализирован пустой строкой, пропускаются все события.

class logging.Filter(name='')

Возвращает экземпляр класса Filter. Если указан name, он задаёт имя регистратора, для которого, вместе с его дочерними элементами, события будут пропускаться через фильтр. Если name – пустая строка, пропускаются все события.

filter(record)

Должна ли указанная запись быть залогирована? Возвращает ноль для 'нет', ненулевое значение для\n'да'. Если это уместно, запись может быть изменена на месте этим\nметодом.

Обратите внимание, что фильтры, прикреплённые к обработчикам, проверяются до того, как событие будет отправлено обработчиком, тогда как фильтры, прикреплённые к регистраторам, проверяются всякий раз, когда событие регистрируется (с помощью debug(), info() и т.д.), перед отправкой события обработчикам. Это означает, что события, созданные дочерними регистраторами, не будут отфильтрованы настройкой фильтра родительского регистратора, если только фильтр не был также применён к этим дочерним регистраторам.

На самом деле не требуется создавать подкласс Filter: можно передать любой экземпляр, имеющий метод filter с той же семантикой.

Изменено в версии 3.2: Не нужно создавать специализированные классы Filter или использовать другие классы с методом filter: можно использовать функцию (или другой вызываемый объект) в качестве фильтра. Логика фильтрации проверяет, есть ли у объекта фильтра атрибут filter: если да, то считается, что это Filter, и вызывается его метод filter(). В противном случае считается, что это вызываемый объект, и он вызывается с записью в качестве единственного параметра. Возвращаемое значение должно соответствовать тому, что возвращает filter().

Хотя фильтры в первую очередь предназначены для фильтрации записей по более сложным критериям, чем уровни, они видят каждую запись, обрабатываемую обработчиком или регистратором, к которому они прикреплены. Это может быть полезно, например, для подсчёта количества записей, обработанных конкретным регистратором или обработчиком, или для добавления, изменения или удаления атрибутов в обрабатываемой записи LogRecord. Очевидно, что изменение LogRecord требует осторожности, но оно позволяет внедрять контекстную информацию в журналы (см. Использование фильтров для внедрения контекстной информации).

16.6.6. Объекты LogRecord

Экземпляры LogRecord автоматически создаются Logger каждый раз, когда что-то регистрируется, и могут быть созданы вручную с помощью makeLogRecord() (например, из сериализованного события, полученного по сети).

class logging.LogRecord(name, level, pathname, lineno, msg, args, exc_info, func=None, sinfo=None)

Содержит всю информацию, относящуюся к регистрируемому событию.

Основная информация передаётся в msg и args, которые объединяются с помощью msg % args для создания поля message записи.

Параметры
  • name – Имя регистратора, используемого для журналирования события, представленного данной записью LogRecord. Обратите внимание, что это имя всегда будет иметь это значение, даже если событие может быть отправлено обработчиком, прикреплённым к другому (родительскому) регистратору.

  • level – Числовой уровень события журналирования (один из DEBUG, INFO и т.д.). Обратите внимание, что он преобразуется в два атрибута LogRecord: levelno для числового значения и levelname для соответствующего имени уровня.

  • pathname – Полное имя пути исходного файла, в котором был выполнен вызов журналирования.

  • lineno – Номер строки в исходном файле, в котором был выполнен вызов журналирования.

  • msg – Сообщение описания события, возможно, форматная строка с заполнителями для переменных данных.

  • args – Переменные данные для объединения с аргументом msg для получения описания события.

  • exc_info – Кортеж исключения с текущей информацией об исключении или None, если информация об исключении отсутствует.

  • func – Имя функции или метода, из которого был вызван вызов журналирования.

  • sinfo – Текстовая строка, представляющая информацию о стеке от основания стека в текущем потоке до вызова журналирования.

getMessage()

Возвращает сообщение для экземпляра LogRecord после объединения любых аргументов, предоставленных пользователем, с сообщением. Если аргумент сообщения, предоставленный пользователем при вызове регистрации, не является строкой, для преобразования в строку вызывается str(). Это позволяет использовать пользовательские классы в качестве сообщений, чей метод __str__ может возвращать фактическую строку формата, которая будет использоваться.

Изменено в версии 3.2: Создание LogRecord стало более настраиваемым благодаря предоставлению фабрики для создания записи. Фабрику можно установить с помощью getLogRecordFactory() и setLogRecordFactory() (см. это для сигнатуры фабрики).

Эту функциональность можно использовать для внедрения собственных значений в объект LogRecord во время его создания. Можно использовать следующий шаблон:

python
old_factory = logging.getLogRecordFactory()

def record_factory(*args, **kwargs):
    record = old_factory(*args, **kwargs)
    record.custom_attribute = 0xdecafbad
    return record

logging.setLogRecordFactory(record_factory)

При таком шаблоне можно объединять несколько фабрик в цепочку, и до тех пор, пока они не перезаписывают атрибуты друг друга или случайно не перезаписывают стандартные атрибуты, перечисленные выше, не должно возникнуть неожиданных проблем.

16.6.7. Атрибуты LogRecord

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

Если используется форматирование {} (str.format()), в качестве заполнителя в строке формата можно использовать {attrname}. Если используется $-форматирование (string.Template), используется форма ${attrname}. В обоих случаях, конечно, attrname заменяется на фактическое имя атрибута.

В случае форматирования {} можно указать флаги форматирования, разместив их после имени атрибута, отделив двоеточием. Например: заполнитель {msecs:03d} отформатирует значение миллисекунд 4 как 004. Для получения полной информации о доступных параметрах см. документацию str.format().

Имя атрибута

Формат

Описание

args

Вам не нужно форматировать это вручную.

Кортеж аргументов, объединённых в msg для создания message, или словарь, значения которого используются для объединения (если аргумент только один и это словарь).

asctime

%(asctime)s

Человекочитаемое время создания LogRecord. По умолчанию имеет вид ‘2003-07-08 16:49:45,896’ (числа после запятой – миллисекундная часть времени).

created

%(created)f

Время создания LogRecord (возвращается time.time()).

exc_info

Вам не нужно форматировать это вручную.

Кортеж исключения (как в sys.exc_info) или, если исключения не произошло, None.

filename

%(filename)s

Часть имени файла из pathname.

funcName

%(funcName)s

Имя функции, содержащей вызов логирования.

levelname

%(levelname)s

Текстовый уровень логирования для сообщения ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL').

levelno

%(levelno)s

Числовой уровень логирования для сообщения (DEBUG, INFO, WARNING, ERROR, CRITICAL).

lineno

%(lineno)d

Номер строки исходного кода, где был сделан вызов логирования (если доступен).

message

%(message)s

Записанное сообщение, вычисляемое как msg % args. Устанавливается при вызове Formatter.format().

модуль

%(module)s

Модуль (часть имени из filename).

msecs

%(msecs)d

Миллисекундная часть времени создания LogRecord.

msg

Вам не нужно форматировать это вручную.

Строка формата, переданная в исходный вызов логирования. Объединяется с args для получения message, или произвольный объект (см. Использование произвольных объектов в качестве сообщений).

имя

%(name)s

Имя регистратора, используемого для логирования вызова.

pathname

%(pathname)s

Полный путь к исходному файлу, где был сделан вызов логирования (если доступен).

процесс

%(process)d

Идентификатор процесса (если доступен).

processName

%(processName)s

Имя процесса (если доступно).

relativeCreated

%(relativeCreated)d

Время в миллисекундах, когда был создан LogRecord, относительно времени загрузки модуля logging.

stack_info

Вам не нужно форматировать это вручную.

Информация о фреймах стека (если доступна) от дна стека в текущем потоке, вплоть до и включая фрейм вызова журналирования, который привёл к созданию этой записи.

поток

%(thread)d

Идентификатор потока (если доступен).

threadName

%(threadName)s

Имя потока (если доступно).

Изменено в версии 3.1: processName был добавлен.

16.6.8. Объекты LoggerAdapter

Экземпляры LoggerAdapter используются для удобной передачи контекстной информации в вызовы логирования. Пример использования см. в разделе добавление контекстной информации в вывод лога.

classlogging.LoggerAdapter(logger, extra)

Возвращает экземпляр LoggerAdapter, инициализированный базовым экземпляром Logger и объектом, похожим на словарь.

process(msg, kwargs)

Изменяет сообщение и/или именованные аргументы, передаваемые в вызов логирования, для вставки контекстной информации. Эта реализация берёт объект, переданный как extra в конструктор, и добавляет его в kwargs с ключом 'extra'. Возвращаемое значение – кортеж (msg, kwargs), содержащий (возможно изменённые) версии переданных аргументов.

В дополнение к вышеуказанному, LoggerAdapter поддерживает следующие методы Logger: debug(), info(), warning(), error(), exception(), critical(), log(), isEnabledFor(), getEffectiveLevel(), setLevel() и hasHandlers(). Эти методы имеют те же сигнатуры, что и их аналоги в Logger, поэтому вы можете использовать экземпляры обоих типов взаимозаменяемо.

Изменено в версии 3.2: Методы isEnabledFor(), getEffectiveLevel(), setLevel() и hasHandlers() были добавлены в LoggerAdapter. Эти методы делегируют выполнение базовому логгеру.

16.6.9. Потокобезопасность

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

Если вы реализуете асинхронные обработчики сигналов с помощью модуля signal, вы можете не иметь возможности использовать логирование из таких обработчиков. Это связано с тем, что реализации блокировок в модуле threading не всегда реентерабельны и поэтому не могут быть вызваны из таких обработчиков сигналов.

16.6.10. Функции уровня модуля

В дополнение к классам, описанным выше, существует ряд функций уровня модуля.

logging.getLogger(name=None)

Возвращает логгер с указанным именем или, если имя равно None, возвращает\nлоггер, который является корневым логгером иерархии. Если указано, имя обычно\nпредставляет собой иерархическое имя, разделённое точками, например ‘a’, ‘a.b’ или ‘a.b.c.d’.\nВыбор этих имён полностью зависит от разработчика, использующего логирование.

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

logging.getLoggerClass()

Возвращает либо стандартный класс Logger, либо последний класс, переданный в setLoggerClass(). Эту функцию можно вызывать из определения нового класса, чтобы установка пользовательского класса Logger не отменяла изменения, уже внесённые другим кодом. Например:

python
class MyLogger(logging.getLoggerClass()):
    # ... override behaviour here
logging.getLogRecordFactory()

Возвращает вызываемый объект, который используется для создания объекта LogRecord.

Новое в версии 3.2: Эта функция предоставлена вместе с setLogRecordFactory(),\nчтобы дать разработчикам больше контроля над тем, как конструируется LogRecord\nпредставляющий событие логирования.

Смотрите setLogRecordFactory() для получения дополнительной информации о том, как вызывается фабрика.

logging.debug(msg, *args, **kwargs)

Регистрирует сообщение с уровнем DEBUG в корневом логгере. msg – это строка форматирования сообщения, а args – аргументы, которые объединяются с msg с помощью оператора форматирования строк. (Обратите внимание, что это означает возможность использования ключевых слов в строке форматирования вместе с единственным аргументом-словарём.)

В kwargs проверяются три именованных аргумента: exc_info – если он не равен false, информация об исключении добавляется в сообщение лога. Если передаётся кортеж исключения (в формате, возвращаемом sys.exc_info()) или экземпляр исключения, используется он; в противном случае вызывается sys.exc_info() для получения информации об исключении.

Второй необязательный именованный аргумент – stack_info, по умолчанию False. Если true, в сообщение журнала добавляется информация о стеке, включая сам вызов журналирования. Обратите внимание, что это не та же информация о стеке, что отображается при указании exc_info: первая – это фреймы стека от дна стека до вызова журналирования в текущем потоке, тогда как вторая – это информация о фреймах стека, которые были развёрнуты после исключения, при поиске обработчиков исключений.

Можно указать stack_info независимо от exc_info, например, чтобы просто показать, как был достигнут определённый участок кода, даже если никаких исключений не возникало. Фреймы стека выводятся после строки заголовка, которая гласит:

text
Stack (most recent call last):

Это имитирует Traceback (most recent call last):, который используется при отображении фреймов исключений.

Третий необязательный именованный аргумент – extra, который можно использовать для передачи словаря, заполняющего __dict__ объекта LogRecord, создаваемого для события логирования, пользовательскими атрибутами. Затем эти пользовательские атрибуты можно использовать по своему усмотрению. Например, их можно встраивать в сообщения. Пример:

python
FORMAT = '%(asctime)-15s %(clientip)s %(user)-8s %(message)s'
logging.basicConfig(format=FORMAT)
d = {'clientip': '192.168.0.1', 'user': 'fbloggs'}
logging.warning('Protocol problem: %s', 'connection reset', extra=d)

выведет примерно следующее:

text
2006-02-08 22:20:02,165 192.168.0.1 fbloggs  Protocol problem: connection reset

Ключи в словаре, передаваемом в extra, не должны совпадать с ключами, используемыми системой логирования. (См. документацию Formatter для получения дополнительной информации о том, какие ключи используются системой логирования.)

При использовании этих атрибутов в сообщениях необходимо соблюдать осторожность. В приведённом выше примере, например, Formatter настроен со строкой форматирования, которая ожидает атрибуты 'clientip' и 'user' в словаре атрибутов LogRecord. Если они отсутствуют, сообщение не будет зарегистрировано, так как возникнет исключение форматирования строки. Поэтому в данном случае необходимо всегда передавать словарь extra с этими ключами.

Хотя это может раздражать, данная возможность предназначена для использования в специализированных ситуациях, например, на многопоточных серверах, где один и тот же код выполняется во множестве контекстов, и возникающие интересные условия зависят от этого контекста (такие как IP-адрес удалённого клиента и имя аутентифицированного пользователя в приведённом выше примере). В таких обстоятельствах, скорее всего, будут использоваться специализированные Formatter с определёнными Handler.

Новое в версии 3.2: Добавлен параметр stack_info.

logging.info(msg, *args, **kwargs)

Регистрирует сообщение с уровнем INFO в корневом логгере. Аргументы интерпретируются как для debug().

logging.warning(msg, *args, **kwargs)

Регистрирует сообщение с уровнем WARNING в корневом логгере. Аргументы интерпретируются как для debug().

Примечание

Существует устаревшая функция warn, которая функционально идентична warning. Поскольку warn устарела, не используйте её – вместо неё используйте warning.

logging.error(msg, *args, **kwargs)

Регистрирует сообщение с уровнем ERROR в корневом логгере. Аргументы интерпретируются как для debug().

logging.critical(msg, *args, **kwargs)

Регистрирует сообщение с уровнем CRITICAL в корневом логгере. Аргументы интерпретируются как для debug().

logging.exception(msg, *args, **kwargs)

Регистрирует сообщение с уровнем ERROR в корневом логгере. Аргументы интерпретируются как для debug(). В сообщение добавляется информация об исключении. Эту функцию следует вызывать только из обработчика исключений.

logging.log(level, msg, *args, **kwargs)

Регистрирует сообщение с уровнем level в корневом логгере. Остальные аргументы интерпретируются как для debug().

Примечание

Вышеупомянутые удобные функции модуля верхнего уровня, которые делегируют корневому логгеру, вызывают basicConfig(), чтобы гарантировать наличие хотя бы одного обработчика. Из-за этого их не следует использовать в потоках в версиях Python ранее 2.7.1 и 3.2, если только до запуска потоков в корневой логгер не был добавлен хотя бы один обработчик. В более ранних версиях Python из-за недостатка потокобезопасности в basicConfig() это может (в редких случаях) привести к многократному добавлению обработчиков в корневой логгер, что, в свою очередь, может привести к появлению нескольких сообщений для одного события.

logging.disable(lvl=CRITICAL)

Предоставляет переопределяющий уровень lvl для всех регистраторов, который имеет приоритет над собственным уровнем регистратора. Когда возникает необходимость временно снизить интенсивность вывода журнала во всем приложении, эта функция может быть полезна. Её действие – отключать все вызовы журналирования с серьезностью lvl и ниже; если вызвать её со значением INFO, то все события INFO и DEBUG будут отброшены, а события серьезности WARNING и выше будут обработаны в соответствии с эффективным уровнем регистратора. Если вызывается logging.disable(logging.NOTSET), этот переопределяющий уровень удаляется, и вывод журнала снова зависит от эффективных уровней отдельных регистраторов.

Обратите внимание: если вы определили какой-либо пользовательский уровень журналирования выше CRITICAL (это не рекомендуется), вы не сможете полагаться на значение по умолчанию для параметра lvl, а должны будете явно указать подходящее значение.

Изменено в версии 3.7: Параметр lvl по умолчанию получил значение CRITICAL. См. Issue #28524 для получения дополнительной информации об этом изменении.

logging.addLevelName(lvl, levelName)

Связывает уровень lvl с текстом levelName во внутреннем словаре, который используется для сопоставления числовых уровней с текстовым представлением, например, когда Formatter форматирует сообщение. Эта функция также может использоваться для определения собственных уровней. Единственные ограничения: все используемые уровни должны быть зарегистрированы с помощью этой функции, уровни должны быть положительными целыми числами и должны возрастать с увеличением серьезности.

Примечание

Если вы собираетесь определять собственные уровни, обратитесь к разделу Пользовательские уровни.

logging.getLevelName(lvl)

Возвращает текстовое представление уровня журналирования lvl. Если уровень является одним из предопределенных уровней CRITICAL, ERROR, WARNING, INFO или DEBUG, то возвращается соответствующая строка. Если вы связали уровни с именами с помощью addLevelName(), то возвращается имя, которое вы связали с lvl. Если передан числовой уровень, соответствующий одному из определенных уровней, возвращается соответствующее строковое представление. В противном случае возвращается строка 'Level %s' % lvl.

Примечание

Уровни внутри являются целыми числами (поскольку их необходимо сравнивать в логике логирования). Эта функция используется для преобразования между целочисленным уровнем и именем уровня, отображаемым в отформатированном выводе журнала с помощью спецификатора формата %(levelname)s (см. атрибуты LogRecord).

Изменено в версии 3.4: В версиях Python до 3.4 этой функции также можно было передавать текстовый уровень, и она возвращала соответствующее числовое значение уровня. Это недокументированное поведение было признано ошибкой и удалено в Python 3.4, но восстановлено в 3.4.2 для сохранения обратной совместимости.

logging.makeLogRecord(attrdict)

Создаёт и возвращает новый экземпляр LogRecord, атрибуты которого определяются attrdict. Эта функция полезна для получения сериализованного (pickled) словаря атрибутов LogRecord, отправленного через сокет, и восстановления его как экземпляра LogRecord на принимающей стороне.

logging.basicConfig(**kwargs)

Выполняет базовую настройку системы логирования, создавая StreamHandler с Formatter по умолчанию и добавляя его в корневой логгер. Функции debug(), info(), warning(), error() и critical() будут автоматически вызывать basicConfig(), если для корневого логгера не определены обработчики.

Эта функция ничего не делает, если для корневого регистратора уже настроены обработчики.

Примечание

Данную функцию следует вызывать из главного потока до запуска других потоков. В версиях Python до 2.7.1 и 3.2, если эта функция вызывается из нескольких потоков, возможно (в редких случаях), что обработчик будет добавлен к корневому логгеру более одного раза, что приведёт к неожиданным результатам, таким как дублирование сообщений в логе.

Поддерживаются следующие именованные аргументы.

Формат

Описание

filename

Указывает, что должен быть создан FileHandler, использующий указанное имя файла, а не StreamHandler.

filemode

Если указан filename, открыть файл в этом mode. По умолчанию 'a'.

format

Использует указанную строку формата для обработчика.

datefmt

Использовать указанный формат даты/времени, принимаемый time.strftime().

style

Если указан format, использовать этот стиль для строки формата. Один из '%', '{' или '$' для printf-стиля, str.format() или string.Template соответственно. По умолчанию '%'.

уровень

Установить уровень корневого логгера в указанный уровень.

поток данных

Использует указанный поток для инициализации StreamHandler. Обратите внимание, что этот аргумент несовместим с filename – если оба присутствуют, возбуждается ValueError.

обработчики

Если указан, это должен быть итерируемый объект с уже созданными обработчиками для добавления в корневой регистратор. Любые обработчики, для которых еще не задан форматировщик, получат форматировщик по умолчанию, созданный в этой функции. Обратите внимание, что этот аргумент несовместим с filename или stream – если указаны оба, возбуждается ValueError.

Изменено в версии 3.2: Был добавлен аргумент style.

Изменено в версии 3.3: Был добавлен аргумент handlers. Были добавлены дополнительные проверки для выявления ситуаций, когда указаны несовместимые аргументы (например, handlers вместе с stream или filename, или stream вместе с filename).

logging.shutdown()

Сообщает системе логирования о необходимости выполнить упорядоченное завершение работы, сбрасывая и закрывая все обработчики. Этот вызов следует производить при завершении приложения, и после этого вызова не следует использовать систему логирования.

logging.setLoggerClass(klass)

Указывает системе логирования использовать класс klass при создании экземпляра регистратора. Класс должен определять __init__() таким образом, чтобы требовался только аргумент name, и __init__() должен вызывать Logger.__init__(). Эта функция обычно вызывается до создания экземпляров регистраторов приложениями, которым требуется пользовательское поведение регистратора.

logging.setLogRecordFactory(фабрика)

Устанавливает вызываемый объект, который используется для создания LogRecord.

Параметры

factory – вызываемый объект-фабрика, используемый для создания экземпляра записи журнала.

Новое в версии 3.2: Эта функция предоставляется вместе с getLogRecordFactory(), чтобы разработчики могли лучше контролировать создание LogRecord, представляющего событие логирования.

Фабрика имеет следующую сигнатуру:

factory(name, level, fn, lno, msg, args, exc_info, func=None, sinfo=None, **kwargs)

имя

Имя регистратора.

уровень

Уровень логирования (числовой).

fn

Полное имя пути к файлу, в котором был сделан вызов логирования.

lno

Номер строки в файле, в котором был сделан вызов логирования.

msg

Сообщение логирования.

args

Аргументы для сообщения логирования.

exc_info

Кортеж исключения или None.

func

Имя функции или метода, вызвавшего вызов логирования.

sinfo

Трассировка стека, такая как предоставляется traceback.print_stack(), показывающая иерархию вызовов.

kwargs

Дополнительные именованные аргументы.

16.6.11. Атрибуты уровня модуля

logging.lastResort

Через этот атрибут доступен «обработчик последней надежды». Это StreamHandler, пишущий в sys.stderr с уровнем WARNING и используемый для обработки событий логирования при отсутствии какой-либо конфигурации логирования. Конечный результат – просто вывод сообщения в sys.stderr. Это заменяет более раннее сообщение об ошибке: «для регистратора XYZ не найдено ни одного обработчика». Если вам по какой-то причине нужно прежнее поведение, lastResort можно установить в None.

Новое в версии 3.2.

16.6.12. Интеграция с модулем warnings

Функция captureWarnings() может использоваться для интеграции logging с модулем warnings.

logging.captureWarnings(захват)

Эта функция используется для включения и выключения захвата предупреждений системой логирования.

Если capture равно True, предупреждения, выпущенные модулем warnings, будут перенаправлены в систему логирования. В частности, предупреждение будет отформатировано с помощью warnings.formatwarning(), и результирующая строка будет записана в регистратор с именем 'py.warnings' с уровнем важности WARNING.

Если capture равно False, перенаправление предупреждений в систему логирования прекратится, и предупреждения будут перенаправляться в исходные места назначения (т.е. те, которые действовали до вызова captureWarnings).

Смотрите также

Модуль logging.config

API конфигурации для модуля логирования.

Модуль logging.handlers

Полезные обработчики, включённые в модуль логирования.

PEP 282 – Система логирования

Предложение, описывающее эту функциональность для включения в стандартную библиотеку Python.

Оригинальный пакет логирования Python

Это исходный код для пакета logging. Версия пакета, доступная на этом сайте, подходит для использования с Python 1.5.2, 2.1.x и 2.2.x, которые не включают пакет logging в стандартную библиотеку.