Сообщения журнала, появляющиеся дважды в журнале Python

Я использую ведение журнала Python, и по какой-то причине все мои сообщения появляются дважды.

У меня есть модуль для настройки ведения журнала:

# BUG: It outputting logging messages twice - not sure why - it not the propagate setting.
def configure_logging(self, logging_file):
    self.logger = logging.getLogger("my_logger")
    self.logger.setLevel(logging.DEBUG)
    self.logger.propagate = 0
    # Format for our loglines
    formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
    # Setup console logging
    ch = logging.StreamHandler()
    ch.setLevel(logging.DEBUG)
    ch.setFormatter(formatter)
    self.logger.addHandler(ch)
    # Setup file logging as well
    fh = logging.FileHandler(LOG_FILENAME)
    fh.setLevel(logging.DEBUG)
    fh.setFormatter(formatter)
    self.logger.addHandler(fh)

Впоследствии я вызываю этот метод для настройки ведения журнала:

if __name__ == '__main__':
    tom = Boy()
    tom.configure_logging(LOG_FILENAME)
    tom.buy_ham()

А затем, скажем, модуль buy_ham, я бы назвал:

self.logger.info('Successfully able to write to %s' % path)

И почему-то все сообщения появляются дважды. Я прокомментировал один из обработчиков потоков, все тот же. Немного странно, не знаю, почему это происходит... lol. Предполагая, что я пропустил что-то очевидное.

Cheers, Виктор

Ответ 1

Вы вызываете configure_logging дважды (возможно, в __init__ метод Boy): getLogger вернет тот же объект, но addHandler не проверяет, был ли аналогичный обработчик уже добавлен в регистратор.

Попробуйте трассировать вызовы этого метода и устранить один из них. Или настройте флаг logging_initialized, инициализированный на False в методе __init__ Boy и измените configure_logging, чтобы ничего не делать, если logging_initialized is True и установить его в True после того, как вы инициализирован регистратор.

Если ваша программа создает несколько экземпляров Boy, вам придется изменить способ работы с глобальной функцией configure_logging, добавляя обработчики, а метод Boy.configure_logging только инициализирует атрибут self.logger.

Другим способом решения этой проблемы является проверка атрибута handlers вашего регистратора:

logger = logging.getLogger('my_logger')
if not logger.handlers:
    # create the handlers and call logger.addHandler(logging_handler)

Ответ 2

Обработчик добавляется каждый раз, когда вы вызываете извне. Попробуйте удалить обработчик после завершения работы:

self.logger.removeHandler(ch)

Ответ 3

Я новичок в python, но для меня это работало (Python 2.7)

while logger.handlers:
     logger.handlers.pop()

Ответ 4

Если вы видите эту проблему, и вы не добавляете обработчик дважды, то см. ответ abarnert здесь

Из docs:

Примечание. Если вы прикрепляете обработчик к регистратору и один или несколько его предков, он может издавать одну и ту же запись несколько раз. В общем, вы не нужно прикреплять обработчик к нескольким регистраторам - если вы просто присоедините его к соответствующему регистратору, который является самым высоким в иерархии регистратора, тогда он увидит все события, зарегистрированные всем потомком loggers, при условии, что их параметр распространения остается равным True. общий сценарий заключается в том, чтобы привязывать обработчики только к корневому журналу и пусть пропаганда позаботится об остальном.

Итак, если вы хотите, чтобы пользовательский обработчик "test", и вы не хотите, чтобы его сообщения также поступали в обработчик root, ответ прост: отключите его флаг распространения:

logger.propagate = False