Как использовать logging.getLogger (__name__) в нескольких модулях - PullRequest
0 голосов
/ 06 июня 2018

Из logging howto для Python 2.7 (мой акцент):

Хорошим соглашением для использования при именовании регистраторов является использование регистратора уровня модуля, вкаждый модуль, который использует журналирование, имеет следующие имена:

logger = logging.getLogger(__name__)

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

Звучит как хороший совет.

Теперь, logging поваренная книга предоставляет пример для нескольких модулей, в которых используется жесткийимена регистраторов вместо константы __name__.В «основном модуле» из примера мы находим

logger = logging.getLogger('spam_application')

, а во «вспомогательном модуле» находим

module_logger = logging.getLogger('spam_application.auxiliary')

Я скопировал этот пример дословно в папку пакета со следующей структурой:

cookbook-example
|- __init__.py
|- main_module.py
|- auxiliary_module.py

Это работает без проблем, производя ожидаемый вывод журнала из обоих основных модулейи вспомогательный модуль, но вот в чем дело:

Если я теперь заменю жестко запрограммированные имена регистраторов на константу __name__, как рекомендовано в logging howto , поваренной книгепример ломается: я получаю сообщения регистрации только от основного модуля, но ничего от вспомогательного модуля.

Я, должно быть, упускаю что-то очевидное.Есть идеи, что я делаю неправильно?

Примечание:

Есть много очень похожих вопросов и связанных ответов, например: 1 , 2 , 3 , 4 , 5 , 6 и многие другие.Тем не менее, ни один из них, кажется, не решает этот конкретный вопрос.

- Правка -

Вот минимальный пример, основанный на примере поваренной книги, с явными строками имени, замененными на __name__.

main_module.py

import logging
import auxiliary_module

# create and configure main logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# create console handler with a higher log level
handler = logging.StreamHandler()
handler.setLevel(logging.DEBUG)
# create formatter and add it to the handler
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
# add the handler to the logger
logger.addHandler(handler)

logger.info('message from main module')
auxiliary_module.some_function()

primary_module.py

import logging

# create logger
module_logger = logging.getLogger(__name__) 

def some_function():
    module_logger.info('message from auxiliary module')

Ответы [ 2 ]

0 голосов
/ 08 июня 2018

Как указал @shmee в этом ответе , иерархия регистратора должна быть явно определена в имени регистратора с использованием точечной нотации.То есть, если имя регистратора в main_module.py, например, 'a', тогда имя регистратора в auxiliary_module.py должно быть 'a.b' (не просто 'b'), чтобы оно могло наследовать конфигурацию регистратора * 1008.*.Это также упоминается в документации getLogger() .

Однако об этом следует позаботиться автоматически при использовании __name__, как указано в инструкции logging.на :

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

Дело в том, что для этого вам нужно правильно использовать __name__, а я этого не делал.

Проблема в моем примере заключается в организации файлов в папке пакета cookbook-example:

И основной модуль, и вспомогательный модуль находятся на одном уровне (т.е. на одном и том же уровнепапка).Итак, как объяснено здесь , __name__ для основного модуля будет тогда '__main__' (как это скрипт верхнего уровня), а __name__ для вспомогательного модуля будет 'auxiliary_module' (то есть имя файла), НЕ '__main__.auxiliary_module'.

В результате регистратор во вспомогательном модуле будет дочерним по отношению к корневому регистратору, а не дочерним по отношению к '__main__' регистратору, и он будеттаким образом, наследуйте конфигурацию корневого регистратора (которая по-прежнему имеет уровень ведения журнала по умолчанию WARNING) вместо конфигурации, указанной в основном модуле.

Итак, чтобы пример работал, у нас есть несколько вариантов:

  1. Заменить getLogger(__name__) в основном модуле на getLogger().Это позволит применить конфигурацию к корневому логгеру и, следовательно, также к логгеру вспомогательного модуля, как предложено @ shmee.

  2. Заменить getLogger(__name__) в вспомогательном модулена getLogger('__main__.' + __name__).Результат будет эквивалентен исходному примеру поваренной книги (за исключением того, что основной регистратор теперь называется '__main__' вместо 'spam_application').

0 голосов
/ 06 июня 2018

Имена регистраторов - это то, что вам не хватает.В этом примере в главном модуле создается регистратор с именем spam_application.Затем создаются обработчики и средства форматирования и добавляются в этот регистратор.

В auxiliary_module создаются регистраторы с именами, которые начинаются с spam_application соответственно.spam_application.auxiliary.Это эффективно создает иерархию регистраторов, которые распространяются на их соответствующих родителей, если явно не отключены.Эта иерархия spam_appliclation <- spam_application.auxiliary <- spam_application.auxiliary.Auxiliary или logger <- module_logger <- self.logger в случае примера с кулинарной книгой.

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

Попробуйтеследующее: Измените метод init вашего класса следующим образом:

def __init__(self):
    self.logger = logging.getLogger('spam_application.auxiliary.Auxiliary')
    print self.logger.parent
    self.logger.info('creating an instance of Auxiliary')

Затем запустите ваш основной модуль один раз с

self.logger = logging.getLogger('spam_application.auxiliary.Auxiliary')

и один раз с

self.logger = logging.getLogger(__name__)

Выходные данныедолжно выглядеть так:

<Logger spam_application.auxiliary (WARNING)> # with explicit logger name
<RootLogger root (WARNING)>                   # using __name__
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...