Вопрос или проблема
Я изменил уровень логирования по умолчанию на 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("теперь это должно показывать")
Объяснение:
-
Функция
set_logger_level
: Эта функция устанавливает уровень логирования для логгера и всех его обработчиков. Это гарантирует, что уровень обработчиков всегда будет соответствовать уровню логгера. -
При использовании: После создания логгера с уровнем INFO вы можете легко изменить уровень на DEBUG, используя новую функцию
set_logger_level
, и все сообщения DEBUG будут отображаться.
Таким образом, вы сможете контролировать вывод ваших логов более гибко и избежать ситуации, когда вы не видите сообщения нужного уровня.