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

Объект Logger модуля logging в Python

Регистратор событий, объект Logger модуля logging

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

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

Регистраторы Logger имеют следующие атрибуты и методы


logger.propagate:

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

Если атрибут logger.propagate имеет значение False, сообщения регистрации не передаются обработчикам регистраторов предков.

Конструктор устанавливает для этого атрибута значение True.

Примечание. Если присоединить обработчик к регистратору Logger и одному или нескольким его предкам, то он может отправлять одну и ту же запись несколько раз. В общем, не нужно подключать обработчик к нескольким регистраторам. Достаточно присоединить его к корневому регистратору, который является самым высоким в иерархии и он увидит все события, записанные всеми регистраторами-потомками, при условии, что они будут передаваться. Для параметра logger.propagate оставлено значение True. Распространенный сценарий использования - это подключить обработчики только к корневому регистратору Logger и позволить распространению позаботиться обо всем остальном.

logger.setLevel(level):

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

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

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

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

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

logger.isEnabledFor(level):

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

logger.getEffectiveLevel():

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

logger.getChild(suffix):

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

logger.debug(msg, *args, **kwargs):

Метод logger.debug() регистрирует сообщение msg с уровнем logging.DEBUG на этом регистраторе Logger.

Аргумент msg - это строка формата сообщения, а *args - аргументы, которые объединяются в msg с помощью оператора форматирования строки. Обратите внимание, это означает, что вы можете использовать ключевые аргументы в строке формата вместе с одним аргументом словаря.

Операция форматирования в стиле printf % не выполняется для msg, если не предоставлены аргументы *args.

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

Подробное описание и поведение аргументов exc_info, stack_info и extra смотрите в документации по функциям регистрации сообщений.

Необязательный ключевой аргумент stacklevel представляет собой уровень стека, который по умолчанию равен 1. Если stacklevel больше 1, то соответствующее количество кадров стека пропускается при вычислении номера строки и имени функции, заданных в LogRecord. Это может быть использовано при ведении журнала помощников, так что записанное имя функции, имя файла и номер строки являются не информацией для вспомогательной функции/метода, а скорее ее вызывающей стороной. Имя этого параметра отражает эквивалент модуля warnings.

Изменено в Python-3.8: добавлен параметр уровня стека stacklevel.

logger.info(msg, *args, **kwargs):

Метод logger.info() регистрирует сообщение msg с уровнем INFO на этом регистраторе.

Аргументы интерпретируются как для метода logger.debug().

logger.warning(msg, *args, **kwargs):

Метод logger.warning() регистрирует сообщение msg с уровнем WARNING на этом регистраторе.

Аргументы интерпретируются как для метода logger.debug().

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

logger.error(msg, *args, **kwargs):

Метод logger.error() регистрирует сообщение msg с уровнем ERROR на этом регистраторе.

Аргументы интерпретируются как для метода logger.debug().

logger.critical(msg, *args, **kwargs):

Метод logger.critical() регистрирует сообщение msg с уровнем CRITICAL на этом регистраторе.

Аргументы интерпретируются как для метода logger.debug().

logger.log(level, msg, *args, **kwargs):

Метод logger.log() регистрирует сообщение msg с целочисленным уровнем level на этом регистраторе.

Аргументы интерпретируются как для метода logger.debug().

logger.exception(msg, *args, **kwargs):

Метод logger.exception() регистрирует сообщение msg с уровнем ERROR на этом регистраторе.

Аргументы интерпретируются как для метода logger.debug().

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

logger.addFilter(filter):

Метод logger.addFilter() добавляет указанный фильтр filter в этот регистратор Logger.

logger.removeFilter(filter):

Метод logger.removeFilter() удаляет указанный фильтр filter из этого регистратора.

logger.filter(record):

Метод logger.filter() применяет фильтры этого регистратора к записи и возвращает True, если запись должна быть обработана.

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

logger.addHandler(hdlr):

Метод logger.addHandler() добавляет указанный обработчик hdlr в этот регистратор.

logger.removeHandler(hdlr):

Метод logger.removeHandler() удаляет указанный обработчик hdlr из этого регистратора.

logger.findCaller(stack_info=False, stacklevel=1):

Метод logger.findCaller() находит исходное имя вызывающего абонента и номер строки. Возвращает имя файла, номер строки, имя функции и информацию о стеке в виде 4-элементного кортежа. Если аргумент stack_info=False, то информация стека возвращается как None.

Параметр stacklevel передается из кода, вызывающего методами logger.debug(), logger.info() и т. д. Если stacklevel больше 1, то пропускается соответствующее количество кадров стека перед определением значений, которые будут возвращены. Как правило, это будет полезно при вызове API журналирования с помощником/оберткой, так что информация в журнале событий будет относится не к помощнику/обертке, а к коду, который ее вызывает.

logger.handle(record):

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

logger.makeRecord(name, level, fn, lno, msg, args, exc_info, func=None, extra=None, sinfo=None):

Метод logger.makeRecord() представляет собой фабричный метод, который может быть переопределен в подклассах, чтобы создавать специализированные объекты LogRecord.

logger.hasHandlers():

Метод logger.hasHandlers() проверяет, настроены ли в этом регистраторе Logger какие-либо обработчики. Это делается путем поиска обработчиков в этом регистраторе и его родителях в иерархии регистратора.

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


Примеры:

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

Код основного модуля:

# test.py
import logging
import aux

# создаем регистратор с именем 'logger'
logger = logging.getLogger('log')
logger.setLevel(logging.DEBUG)

# создаем файловый обработчик, который
# регистрирует отладочные сообщения
fh = logging.FileHandler('spam.log')
fh.setLevel(logging.DEBUG)

# создаем консольный обработчик 
# с более высоким уровнем журнала
ch = logging.StreamHandler()
ch.setLevel(logging.ERROR)

# создаем форматтер и добавляем его в обработчики
fmtstr = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
fmtdate = '%H:%M:%S'
formatter = logging.Formatter(fmtstr, fmtdate)

# создаем форматтер в обработчики
fh.setFormatter(formatter)
ch.setFormatter(formatter)

# добавляем настроенные обработчики в логгер
logger.addHandler(fh)
logger.addHandler(ch)


# вызов функций, регистрирующих 
# события в коде
logger.info('создание объекта Auxiliary')
a = auxiliary.Auxiliary()
logger.info('объект Auxiliary создан')
logger.info('вызов метода .something')
a.something()
logger.info('вызов .something закончен')
logger.info('вызов some_func()')
auxiliary.some_func()
logger.info('работа с Auxiliary закончена')

Для приложения будет полезно записывать все сообщения всех уровней логирования в текстовый файл, одновременно регистрируя уровень ERROR или выше в консоли. Что бы настроить такое поведение, необходимо определить соответствующий обработчик handler как показано в примере выше. Класс logger.addHandler() не имеет минимальной или максимальной квоты для количества добавляемых обработчиков.

Код импортируемого модуля.

# aux.py
import logging

# создание регистратора с именем log.aux
module = logging.getLogger('log.aux')

class Auxiliary:
    def __init__(self):
        # создание регистратора с именем log.aux.Auxiliary
        self.logger = logging.getLogger('log.aux.Auxiliary')
        self.logger.debug('__Init__ Auxiliary')

    def something(self):
        self.logger.debug('start .something')
        a = 1 + 1
        self.logger.debug('end .something')

def some_func():
    module.debug('call to some_func')

Обратите внимание на имена регистраторов, создаваемых в импортируемом модуле. Имена должны соблюдать иерархию, т. е. в данном случае, в модуле aux.py имя регистратора должно начинаться с имени корневого регистратора 'log.'. Передаваемое имя в logging.getLogger() представляет собой ссылку на объект регистратора и если getLogger() не находит объекта с соответствующим именем, то он считает себя корневым регистратором. Другими словами, если не соблюдать это правило, то соответствующие сообщения не будут записываться в файл или выводится на консоль.

Вывод будет выглядеть так:

08:52:46 - log - INFO - создание объекта Auxiliary
08:52:46 - log.aux.Auxiliary - DEBUG - __Init__ Auxiliary
08:52:46 - log - INFO - объект Auxiliary создан
08:52:46 - log - INFO - вызов метода .something
08:52:46 - log.aux.Auxiliary - DEBUG - start .something
08:52:46 - log.aux.Auxiliary - DEBUG - end .something
08:52:46 - log - INFO - вызов .something закончен
08:52:46 - log - INFO - вызов some_func()
08:52:46 - log.aux - DEBUG - call to some_func
08:52:46 - log - INFO - работа с Auxiliary закончена

Возможность создания новых обработчиков с фильтрами более высокой или более низкой важности может быть очень полезна при написании и тестировании приложения. Вместо использования функций print() для отладки используйте метод logger.debug(): в отличие от операторов print(), которые придется удалить или закомментировать позже, функции logger.debug() могут оставаться нетронутыми в исходном коде и оставаться неактивными, пока они вам не понадобятся снова. Единственное изменение, которое необходимо сделать - это изменить уровень логирования и/или обработчика для отладки.