Я не планировал публиковать свой собственный ответ, но я не согласен с другим ответом, поэтому здесь мы идем:)
Не вижу смысла в создании базового модуля протоколирования . Уже есть один, он называется logging
, и, на мой взгляд, он отлично работает.
У изложенного решения в другом ответе есть недостаток: хотя он создает один единственный регистратор *, он также создает несколько обработчиков и форматеров, один экземпляр которого устанавливается каждый раз BaseLogging
.
* Поскольку __name__
не изменяется в BaseLogging
, независимо от того, откуда вы его импортируете. Это также то, что нарушает атрибут %(module)s
и вызывает 'hacks' с inspect
, чтобы получить имя модуля вызывающего абонента
core.py
from base_logging import BaseLogging
class myclass():
def __init__(self):
# just instantiate the class, don't even call any method on it
blogger = BaseLogging()
main.py
from base_logging import BaseLogging
import core
blog = BaseLogging() # fist instance, one handler and one formatter attached to the logger
core.myclass() # creates the second instance during instantiation
blog.debug("Can I get a sibling, mommy?")
Примечание: в base_logging.BaseLogging я добавил self.logger.setLevel(logging.DEBUG)
в инициализатор, чтобы сделать эту работу без необходимости реализации методов для WARNING
и выше.
Если вы сейчас запустите main.py
, ваш журнал будет выглядеть так:
2019-01-16 11:54:23,305:main,DEBUG:Can I get a sibling, mommy?
2019-01-16 11:54:23,305:main,DEBUG:Can I get a sibling, mommy?
logging
уже работает в глобальном пространстве имен. Регистраторы, которые вы создаете и настраиваете один раз, доступны из любого места в вашем процессе. Вам просто нужно знать, какой просить. Вы можете проверить logging.Logger.manager.loggerDict
в любое время и из любого места, чтобы увидеть известные на данный момент регистраторы.
(Примечание: это, вероятно, не должно рассматриваться как часть официального API, поэтому я бы предпочел не использовать его в производстве, но Я нашел это полезным во время разработки и для отладки) :
main.py
[your main.py up to this point]
print("before:", logging.Logger.manager.loggerDict)
#logger.info("I am in main.")
core.myclass()
print("after:", logging.Logger.manager.loggerDict)
core.py
class myclass():
def __init__(self):
logger = logging.getLogger("main")
print("in myclass", logging.Logger.manager.loggerDict)
#logger.debug("Debug message")
#logger.warn("Warning message")
Выход:
before: {'__main__': <Logger __main__ (DEBUG)>}
in myclass {'__main__': <Logger __main__ (DEBUG)>, 'main': <Logger main (WARNING)>}
after: {'__main__': <Logger __main__ (DEBUG)>, 'main': <Logger main (WARNING)>}
Итак, все, что вам нужно, это убедиться, что вы используете одно и то же имя, если хотите получить один и тот же регистратор, т.е. используйте logger = logging.getLogger("__main__")
в этом контексте или, что еще лучше, используйте выделенное имя прямо из начать, чтобы избежать проблем с __name__
, имеющими разные значения в зависимости от того, выполняется сценарий или импортирован.
main.py
[...]
logger = logging.getLogger("main_logger")
[...]
core.py
# in myclass.__init__()
[...]
logger = logging.getLogger("main_logger")
[...]
=> main.log
I am in main.
Debug message
Warning message