инициализация логгера Python на уровне=20 (INFO), чтобы не показывать отладочную информацию, если я позже изменю на уровень=10 (DEBUG)

Вопрос или проблема

Я изменил уровень логирования по умолчанию на logging.INFO (20) вместо Logging.DEBUG (10), но тогда он не показывает сообщения отладчика, если я позже в коде изменю уровень журнала на ‘DEBUG’:

Старая конфигурация работает хорошо:

>>> import mylog
>>> log1 = mylog.mylogger('log1',level=10) # по умолчанию DEBUG
добавлен журнал log1 уровня:10
>>> log1
<Logger log1 (DEBUG)>
>>> log1.debug("работает")
20241007163742.800|DEBUG|<stdin>:1|работает
>>> log1.setLevel(20)
>>> log1
<Logger log1 (INFO)>
>>> log1.info("работает")
20241007163825.042|INFO|<stdin>:1|работает
>>> log1.debug("не должно отображаться") 
>>> 

Я также могу вернуться к отладке, и это работает:

>>> log1.setLevel(10)
>>> log1
<Logger log1 (DEBUG)>
>>> log1.debug("работает")
20241007164010.113|DEBUG|<stdin>:1|работает

Все хорошо, кроме того, что логирование по умолчанию – это DEBUG, что записывает немного слишком много, если я не изменяю уровень журнала.

Но если я устанавливаю по умолчанию level=20, я не вижу DEBUG после log2.setLevel(10):

>>> log2 = mylog.mylogger('log2',level=20) # по умолчанию INFO
добавлен журнал log2 уровня:20
>>> log2
<Logger log2 (INFO)>
>>> log2.info("работает")
20241007164505.921|INFO|<stdin>:1|работает
>>> log2.debug("не должно отображаться") 
>>> log2.setLevel(10)
>>> log2
<Logger log2 (DEBUG)>
>>> log2.info("работает как прежде")
20241007164628.199|INFO|<stdin>:1|работает как прежде
>>> log2.debug("почему это не отображается")
>>> 

Мой упрощенный модуль журнала mylog.py:

import logging
def mylogger(name:str, level:int=logging.INFO) -> logging.Logger:
    """ журнал по умолчанию """
    logger = logging.getLogger(name)
    if logger.hasHandlers():
        print(f"журнал {name} уже имеет обработчик")
    else:
        logger.setLevel(level)
        console_fmt = "%(asctime)s.%(msecs)03d|%(levelname)s|%(pathname)s:%(lineno)d|%(message)s"
        datefmt = "%Y%m%d%H%M%S"
        ch = logging.StreamHandler()
        ch.setLevel(level)
        ch.setFormatter(logging.Formatter(file_fmt, datefmt))
        logger.addHandler(ch)
        logger.propagate = False
        print(f"добавлен журнал {name} уровня:{logger.level}")
    return logger

Может быть, это уровень StreamHandler()?

Как я могу проверить это после его настройки?

>>> loggers = [logging.getLogger(name) for name in logging.root.manager.loggerDict]
>>> loggers
[<Logger log1 (DEBUG)>, <Logger log2 (DEBUG)>]

Ответ или решение

Проблема, с которой вы столкнулись, связана с тем, что уровень логирования для обработчика (StreamHandler) не обновляется автоматически, когда вы изменяете уровень логирования самого логгера. Давайте рассмотрим, как это можно исправить.

Ваша текущая реализация инициализации логгера создает обработчик и устанавливает его уровень логирования равным уровню логгера. Однако при изменении уровня логгера позднее, уровень обработчика остается прежним, что приводит к тому, что сообщения DEBUG не отображаются, если уровень логгера был установлен на INFO.

Чтобы исправить это, вы можете обновить уровень логирования обработчика при изменении уровня логгера. Также стоит добавить проверку и установку уровня для обработчиков, чтобы они всегда соответствовали текущему уровню логгера.

Вот как это может выглядеть:

import logging

def mylogger(name: str, level: int = logging.INFO) -> logging.Logger:
    """ default logger """
    logger = logging.getLogger(name)

    if logger.hasHandlers():
        print(f"logger {name} уже имеет обработчик")
    else:
        logger.setLevel(level)
        console_fmt = "%(asctime)s.%(msecs)03d|%(levelname)s|%(pathname)s:%(lineno)d|%(message)s"
        datefmt = "%Y%m%d%H%M%S"
        ch = logging.StreamHandler()
        ch.setLevel(level)  # Устанавливаем уровень для обработчика
        ch.setFormatter(logging.Formatter(console_fmt, datefmt))
        logger.addHandler(ch)
        logger.propagate = False
        print(f"добавлен логгер {name} с уровнем: {logger.level}")

    return logger

def set_logger_level(logger: logging.Logger, level: int):
    """ Устанавливает уровень логгера и его обработчиков """
    logger.setLevel(level)
    for handler in logger.handlers:
        handler.setLevel(level)  # Устанавливаем уровень для каждого обработчика
    print(f"логгер {logger.name} установлен на уровень: {level}")

# Пример использования
log2 = mylogger('log2', level=20)  # По умолчанию INFO
log2.info("работает")
log2.debug("не должно показывать")

# Изменим уровень логгера
set_logger_level(log2, 10)  # Установить уровень DEBUG
log2.info("работает как прежде")
log2.debug("теперь это должно показывать")

Объяснение:

  1. Функция set_logger_level: Эта функция устанавливает уровень логирования для логгера и всех его обработчиков. Это гарантирует, что уровень обработчиков всегда будет соответствовать уровню логгера.

  2. При использовании: После создания логгера с уровнем INFO вы можете легко изменить уровень на DEBUG, используя новую функцию set_logger_level, и все сообщения DEBUG будут отображаться.

Таким образом, вы сможете контролировать вывод ваших логов более гибко и избежать ситуации, когда вы не видите сообщения нужного уровня.

Оцените материал
Добавить комментарий

Капча загружается...