Вход в систему на Python. Обработчики и дубликаты консоли

#python #logging

#python #ведение журнала

Вопрос:

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

 def main()

  # ....
  # Create logger
  logging.basicConfig(filemode='w', level=logging.DEBUG)
  logger = logging.getLogger(__name__)
  logger.setLevel(logging.DEBUG)

  # Create file handler for DEBUG and above
  fh1 = logging.FileHandler(__name__   '.debug.log')
  fh1.setLevel(logging.DEBUG)

  # Create file handler for INFO and above
  fh2 = logging.FileHandler(__name__   '.info.log')
  fh2.setLevel(logging.INFO)

  # Create console handler with INFO and above
  ch = logging.StreamHandler()
  ch.setLevel(logging.INFO)

  # Add all the handlers to the logger
  logger.addHandler(fh1)
  logger.addHandler(fh2)
  logger.addHandler(ch)
  # ....
  

Затем, когда я вызываю

 logger.info("this is an INFO message")
logger.debug("this is a DEBUG message")
  

Я получаю следующее на консоли:

 this is an INFO message
INFO:__main__:this is an INFO message
this is a DEBUG message
DEBUG:__main__:this is a DEBUG message
  

Хотя я ожидал видеть только INFO сообщения в консоли (поскольку я указал logging.info выше для StreamHandler ). Почему я получаю эти дубликаты?

Мои .debug.log и info.log файлы содержат только сообщения на правильном уровне, но их форматирование не включает в себя префиксы INFO:__main__ ни DEBUG:__main__ . Почему их форматирование отличается?

Комментарии:

1. зачем устанавливать level =DEBUG, я всегда использую logging.basicConfig(format='%(asctime)s %(message)s') Также имейте в виду, что экземпляры logger являются одноэлементными, поэтому, возможно, установка 2 обработчиков заставляет его повторять сообщения на 2 уровнях: INFO и DEBUG.

Ответ №1:

 logging.basicConfig(filemode='w', level=logging.DEBUG)
  

создает StreamHandler . Итак, ваш код создает два StreamHandlers , один с уровнем ведения журнала DEBUG , а другой с уровнем INFO .

basicConfig это удобная функция. Если вы хотите создать свои собственные обработчики, вызывать их не обязательно basicConfig . (Или вы можете вызвать basicConfig и добавить дополнительные обработчики …)


Если вы не указываете имя файла при вызове basicConfig , то в корневой регистратор добавляется StreamHandler . Это код внутри basicConfig функции:

 if handlers is None:
    filename = kwargs.get("filename")
    if filename:
        mode = kwargs.get("filemode", 'a')
        h = FileHandler(filename, mode)
    else:
        stream = kwargs.get("stream")
        h = StreamHandler(stream)