Использование регистрации Python в нескольких модулях
у меня есть небольшой проект python, который имеет следующую структуру -
Project
-- pkg01
-- test01.py
-- pkg02
-- test02.py
-- logging.conf
Я планирую использовать модуль ведения журнала по умолчанию для печати сообщений в stdout и файл журнала.
Для использования модуля ведения журнала требуется некоторая инициализация -
import logging.config
logging.config.fileConfig('logging.conf')
logger = logging.getLogger('pyApp')
logger.info('testing')
в настоящее время я выполняю эту инициализацию в каждом модуле, прежде чем начать регистрировать сообщения. Можно ли выполнить эту инициализацию только один раз в одном месте, чтобы одни и те же параметры повторно использовались путем ведения журнала по всему проект?
7 ответов:
лучше всего в каждом модуле иметь регистратор, определенный следующим образом:
import logging logger = logging.getLogger(__name__)в верхней части модуля, а затем в другом коде в модуле, например,
logger.debug('My message with %s', 'variable data')Если вам нужно разделить активность ведения журнала внутри модуля, используйте, например,
loggerA = logging.getLogger(__name__ + '.A') loggerB = logging.getLogger(__name__ + '.B')и журнала
loggerAиloggerBпо мере необходимости.в вашей основной программе или программах, например:
def main(): "your program code" if __name__ == '__main__': import logging.config logging.config.fileConfig('/path/to/logging.conf') main()или
def main(): import logging.config logging.config.fileConfig('/path/to/logging.conf') # your program code if __name__ == '__main__': main()посмотреть здесь для регистрации из нескольких модулей и здесь для регистрации конфигурации кода, который будет использоваться в качестве библиотечного модуля другим кодом.
обновление: при вызове
fileConfig(), вы можете указатьdisable_existing_loggers=Falseесли вы используете Python 2.6 или более поздней версии (см. документы для получения дополнительной информации). Значение по умолчанию:Trueдля обратной совместимости, что приводит к отключению всех существующих регистраторовfileConfig()если они или их предок явно назван в конфигурации. Со значением, установленным вFalseсуществующие лесозаготовители оставили в покое. При использовании Python 2.7 / Python 3.2 или более поздней версии, вы можете рассмотретьdictConfig()API, который лучше, чемfileConfig()как это дает больше контроля над конфигурацией.
фактически каждый регистратор является дочерним по отношению к родительскому регистратору пакетов (т. е.
package.subpackage.moduleнастройки наследует отpackage.subpackage), поэтому все, что вам нужно сделать, это просто настроить корневой регистратор. Это может быть достигнуто с помощьюlogging.config.fileConfig(ваша собственная конфигурация для регистраторов) илиlogging.basicConfig(устанавливает корневой регистратор). Настройка входа в модуль ввода (__main__.pyили все, что вы хотите запустить, напримерmain_script.py.__init__.pyработает)используя basicConfig:
# package/__main__.py import logging import sys logging.basicConfig(stream=sys.stdout, level=logging.INFO)С помощью fileConfig:
# package/__main__.py import logging import logging.config logging.config.fileConfig('logging.conf')и затем создать каждый регистратор с помощью:
# package/submodule.py # or # package/subpackage/submodule.py import logging log = logging.getLogger(__name__) log.info("Hello logging!")для получения дополнительной информации см. Расширенный Журнал Учебник.
Я всегда делаю это, как показано ниже.
используйте один файл python для настройки моего журнала как одноэлементный шаблон с именем'
log_conf.py'#-*-coding:utf-8-*- import logging.config def singleton(cls): instances = {} def get_instance(): if cls not in instances: instances[cls] = cls() return instances[cls] return get_instance() @singleton class Logger(): def __init__(self): logging.config.fileConfig('logging.conf') self.logr = logging.getLogger('root')в другом модуле просто импортируйте конфигурацию.
from log_conf import Logger Logger.logger.info("Hello World")Это одноэлементный шаблон для регистрации, просто и эффективно.
@Yarkee решение казалось лучше. Я хотел бы добавить кое-что к этому -
class Singleton(type): _instances = {} def __call__(cls, *args, **kwargs): if cls not in cls._instances.keys(): cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) return cls._instances[cls] class LoggerManager(object): __metaclass__ = Singleton _loggers = {} def __init__(self, *args, **kwargs): pass @staticmethod def getLogger(name=None): if not name: logging.basicConfig() return logging.getLogger() elif name not in LoggerManager._loggers.keys(): logging.basicConfig() LoggerManager._loggers[name] = logging.getLogger(str(name)) return LoggerManager._loggers[name] log=LoggerManager().getLogger("Hello") log.setLevel(level=logging.DEBUG)поэтому LoggerManager может быть подключаемым ко всему приложению. Надеюсь, что это имеет смысл и значение.
бросая в другом решении.
в главном модуле init у меня есть что-то вроде:
import logging def get_module_logger(mod_name): logger = logging.getLogger(mod_name) handler = logging.StreamHandler() formatter = logging.Formatter( '%(asctime)s %(name)-12s %(levelname)-8s %(message)s') handler.setFormatter(formatter) logger.addHandler(handler) logger.setLevel(logging.DEBUG) return loggerтогда в каждом классе мне нужен регистратор, я делаю:
from [modname] import get_module_logger logger = get_module_logger(__name__)когда журналы пропущены, вы можете различать их источник по модулю, из которого они пришли.
некоторые из этих ответов предполагают, что в верхней части модуля вы
import logging logger = logging.getLogger(__name__)насколько я понимаю, это считается очень плохая практика. Причина в том, что конфигурация файла отключит все существующие регистраторы по умолчанию. Е. Г.
#my_module import logging logger = logging.getLogger(__name__) def foo(): logger.info('Hi, foo') class Bar(object): def bar(self): logger.info('Hi, bar')и в главном модуле :
#main import logging # load my module - this now configures the logger import my_module # This will now disable the logger in my module by default, [see the docs][1] logging.config.fileConfig('logging.ini') my_module.foo() bar = my_module.Bar() bar.bar()теперь журнал, указанный в журнале.ini будет пустым, так как существующий регистратор был отключен вызовом fileconfig.
пока есть конечно, можно обойти это (disable_existing_Loggers=False), реально многие клиенты вашей библиотеки не будут знать об этом поведении и не будут получать ваши журналы. Сделайте это легко для ваших клиентов, всегда вызывая ведение журнала.getLogger локально. Наконечник шляпы : я узнал об этом поведении от сайт Виктора Лина.
поэтому хорошей практикой является вместо этого всегда вызывать ведение журнала.getLogger локально. Е. Г.
#my_module import logging logger = logging.getLogger(__name__) def foo(): logging.getLogger(__name__).info('Hi, foo') class Bar(object): def bar(self): logging.getLogger(__name__).info('Hi, bar')кроме того, если вы используете fileconfig в вашем главное, установить disable_existing_loggers=false, то только в случае, если ваши дизайнеры библиотека уровень использования экземпляров модуль регистратора.
вы также можете придумать что-то вроде этого!
def get_logger(name=None): default = "__app__" formatter = logging.Formatter('%(levelname)s: %(asctime)s %(funcName)s(%(lineno)d) -- %(message)s', datefmt='%Y-%m-%d %H:%M:%S') log_map = {"__app__": "app.log", "__basic_log__": "file1.log", "__advance_log__": "file2.log"} if name: logger = logging.getLogger(name) else: logger = logging.getLogger(default) fh = logging.FileHandler(log_map[name]) fh.setFormatter(formatter) logger.addHandler(fh) logger.setLevel(logging.DEBUG) return loggerтеперь вы можете использовать несколько регистраторов в одном модуле и во всем проекте, если выше определено в отдельном модуле и импортировано в другие модули, требуется ведение журнала.
a=get_logger("__app___") b=get_logger("__basic_log__") a.info("Starting logging!") b.debug("Debug Mode")
Comments