Ответ 1
Как комментарии @offbyone, можно добавить избыточных обработчиков к одному экземпляру регистратора. документы python для ведения журнала говорят -
"Несколько вызовов в getLogger() с тем же именем возвращают ссылку на один и тот же объект журнала."
Поэтому нам не нужно беспокоиться о том, чтобы сделать реализацию синглтонной, как это уже есть.
К сожалению, для обработчиков, связанных с одним и тем же экземпляром регистратора, то же самое не верно. Могут быть дублированные обработчики.
Пример -
-
Скопируйте этот код и сохраните его в main.py
import logging print 'inside main.py', print '-'*50 def logger(): print 'initializing logger....' logPath = '.' fileName = 'temp' # configure log formatter logFormatter = logging.Formatter("%(asctime)s [%(filename)s] [%(funcName)s] [%(levelname)s] [%(lineno)d] %(message)s") # configure file handler fileHandler = logging.FileHandler("{0}/{1}.log".format(logPath, fileName)) fileHandler.setFormatter(logFormatter) # configure stream handler consoleHandler = logging.StreamHandler() consoleHandler.setFormatter(logFormatter) # get the logger instance logger = logging.getLogger(__name__) # set the logging level logger.setLevel(logging.DEBUG) print 'adding handlers- ' #if not len(logger.handlers): logger.addHandler(fileHandler) logger.addHandler(consoleHandler) print 'logger initialized....\n' print 'associated handlers - ', len(logger.handlers) for handler in logger.handlers: print handler print return logger main_logger = logger() main_logger.info('utilizing main.py logger.') print 'exiting main.py', print '-'*50
-
и следующий код в sub.py
print 'inside sub.py', print '-'*50 print 'importing main.py' import main print 'imported main.py' import logging print 'getting logger instance in sub' sub_logger = main.logger() print 'got logger instance in sub' sub_logger.info("utilizing sub_logger") print 'exiting sub.py', print '-'*50
-
Запустите sub.py
[email protected]:~/code/so$ python sub.py inside sub.py -------------------------------------------------- importing main.py inside main.py -------------------------------------------------- initializing logger.... adding handlers- logger initialized.... associated handlers - 2 <logging.FileHandler object at 0x7f7158740c90> <logging.StreamHandler object at 0x7f7158710b10> 2015-08-04 07:41:01,824 [main.py] [<module>] [INFO] [41] utilizing main.py logger. exiting main.py -------------------------------------------------- imported main.py getting logger instance in sub initializing logger.... adding handlers- logger initialized.... associated handlers - 4 # <===== 4 handlers (duplicates added) <logging.FileHandler object at 0x7f7158740c90> <logging.StreamHandler object at 0x7f7158710b10> <logging.FileHandler object at 0x7f7158710bd0> <logging.StreamHandler object at 0x7f7158710c10> got logger instance in sub 2015-08-04 07:41:01,824 [sub.py] [<module>] [INFO] [10] utilizing sub_logger 2015-08-04 07:41:01,824 [sub.py] [<module>] [INFO] [10] utilizing sub_logger exiting sub.py --------------------------------------------------
Следовательно, несколько вызовов метода, возвращающих один и тот же журнал, добавили дублирующие обработчики.
Теперь, для вашего вопроса -
есть ли способ проверить, существует ли уже обработчик
Да, есть -
logger.handlers
возвращает список всех обработчиков, связанных с данным logger
.
Прежде чем добавлять обработчики к экземпляру регистратора, не добавляйте дубликаты обработчиков В main.py просто не комментируйте строку с надписью if not len(logger.handlers):
и отступом следующие две строки:
if not len(logger.handlers):
logger.addHandler(fileHandler)
logger.addHandler(consoleHandler)
Теперь снова запустите sub.py
[email protected]:~/code/so$ python sub.py
inside sub.py --------------------------------------------------
importing main.py
inside main.py --------------------------------------------------
initializing logger....
adding handlers-
logger initialized....
associated handlers - 2
<logging.FileHandler object at 0x7fd67a891c90>
<logging.StreamHandler object at 0x7fd67a862b10>
2015-08-04 08:14:45,620 [main.py] [<module>] [INFO] [41] utilizing main.py logger.
exiting main.py --------------------------------------------------
imported main.py
getting logger instance in sub
initializing logger....
adding handlers-
logger initialized....
associated handlers - 2 # <===== Still 2 handlers (no duplicates)
<logging.FileHandler object at 0x7fd67a891c90>
<logging.StreamHandler object at 0x7fd67a862b10>
got logger instance in sub
2015-08-04 08:14:45,620 [sub.py] [<module>] [INFO] [10] utilizing sub_logger
exiting sub.py --------------------------------------------------
Кроме того, если вы хотите ограничить тип обработчиков, добавляемых в экземпляр журнала, вы можете сделать что-то вроде этого -
print 'adding handlers- '
# allows to add only one instance of file handler and stream handler
if len(logger.handlers) > 0:
print 'making sure we do not add duplicate handlers'
for handler in logger.handlers:
# add the handlers to the logger
# makes sure no duplicate handlers are added
if not isinstance(handler, logging.FileHandler) and not isinstance(handler, logging.StreamHandler):
logger.addHandler(fileHandler)
print 'added file handler'
logger.addHandler(consoleHandler)
print 'added stream handler'
else:
logger.addHandler(fileHandler)
logger.addHandler(consoleHandler)
print 'added handlers for the first time'
Надеюсь, это поможет!
Edit:
К сожалению, те же не верно для связанных с обработчиками с тем же экземпляром регистратора. Может быть дублировано обработчики прилагаются.
Оказывается, что это выше утверждение не совсем верно.
Предположим, что мы создали и сконфигурировали регистратор под названием "main_logger" в основном модуле (который просто настраивает регистратор, ничего не возвращает).
# get the logger instance
logger = logging.getLogger("main_logger")
# configuration follows
...
Теперь в подмодуле, если мы создаем дочерний логгер после иерархии именования "main_logger.sub_module_logger", нам не нужно его настраивать в подмодуле. Достаточно просто создать регистратор по иерархии именования.
# get the logger instance
logger = logging.getLogger("main_logger.sub_module_logger")
# no configuration needed
# it inherits the configuration from the parent logger
...
И он не добавит дублирующий обработчик.