Вход в один файл из разных скриптов? - PullRequest
0 голосов
/ 15 января 2019

У меня есть верхний уровень main.py, который вызывает core.py. Я бы хотел, чтобы оба файла записывались в одно и то же время. Мой код:

Файл main.py:

import core

import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
logger.addHandler(ch)

fh = logging.FileHandler("main.log",mode="w")
fh.setLevel(logging.DEBUG)
logger.addHandler(fh)

logger.info("I am in main.")

core.myclass()

Файл core.py:

import logging
class myclass():
    def __init__(self):
        logger = logging.getLogger("main")
        print(logger)
        logger.debug("Debug message")
        logger.warn("Warning message")

Насколько я понимаю, линия logger = logging.getLogger("main") должен получить ссылку на исходный журнал, поэтому мне не нужно настраивать его снова. Однако сообщения от core.py имеют уровень предупреждения по умолчанию и не записываются в файл.

Есть ли способ сохранить одинаковые настройки для разных модулей?

Ответы [ 2 ]

0 голосов
/ 16 января 2019

Я не планировал публиковать свой собственный ответ, но я не согласен с другим ответом, поэтому здесь мы идем:)

Не вижу смысла в создании базового модуля протоколирования . Уже есть один, он называется 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
0 голосов
/ 15 января 2019

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

Образец будет как ниже

class BaseLogging():

    def __init__(self):
        self.logger = logging.getLogger(__name__)
        self.logger.setLevel(logging.INFO)
        self.formatter = logging.Formatter('%(asctime)s:%(mod_name)s,%(levelname)s:%(message)s')
        self.file_handler = logging.FileHandler('debug.log')
        self.file_handler.setFormatter(self.formatter)
        self.logger.addHandler(self.file_handler)

    def debug(self, msg):
        module_stack = inspect.stack()[1][1]
        mod_name = inspect.getmodulename(module_stack)
        d = {'mod_name': mod_name}
        self.logger.debug(msg, extra=d)

Я только показал код для отладки здесь, но вы также можете написать методы для предупреждения, критических и все.

Затем просто импортируйте этот BaseLogging в нужный вам модуль, и вы сможете легко регистрировать ваши сообщения. Регистратор запишет все сообщения журнала в один файл, а также укажет модуль, из которого записана запись журнала.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...