我试图为一个模块设置日志记录,并有以下最小的可复制的例子...
import sys
from pathlib import Path
from datetime import datetime
import logging
start = datetime.now()
LOG_CONFIG = logging.basicConfig(
filename=Path().cwd().stem + f"-{start.strftime('%Y-%m-%d-%H-%M-%S')}.log", filemode="w"
)
LOG_FORMATTER = logging.Formatter(
fmt="[I %(levelname)-8s : %(message)s]"
)
LOG_DEBUG_FORMATTER = logging.Formatter(
fmt="[D %(levelname)-8s : %(message)s]"
)
LOG_ERROR_FORMATTER = logging.Formatter(
fmt="[E %(levelname)-8s : %(message)s]"
)
LOG_WARNING_FORMATTER = logging.Formatter(
fmt="[W %(levelname)-8s : %(message)s]"
)
LOGGER_NAME = "test"
def setup_logger(log_name: str = LOGGER_NAME) -> logging.Logger:
out_stream_handler = logging.StreamHandler(sys.stdout)
out_stream_handler.propagate = False
out_stream_handler.setLevel(logging.INFO)
out_stream_handler.setFormatter(LOG_FORMATTER)
debug_stream_handler = logging.StreamHandler(sys.stderr)
debug_stream_handler.propagate = False
debug_stream_handler.setLevel(logging.DEBUG)
debug_stream_handler.setFormatter(LOG_DEBUG_FORMATTER)
err_stream_handler = logging.StreamHandler(sys.stderr)
err_stream_handler.propagate = False
err_stream_handler.setLevel(logging.ERROR)
err_stream_handler.setFormatter(LOG_ERROR_FORMATTER)
warning_stream_handler = logging.StreamHandler(sys.stderr)
warning_stream_handler.propagate = False
warning_stream_handler.setLevel(logging.WARNING)
warning_stream_handler.setFormatter(LOG_WARNING_FORMATTER)
logger = logging.getLogger(log_name)
logger.setLevel(logging.INFO)
logger.propagate = False
if logger.hasHandlers():
logger.handlers = []
if not logger.handlers:
logger.addHandler(out_stream_handler)
logger.addHandler(debug_stream_handler)
logger.addHandler(err_stream_handler)
logger.addHandler(warning_stream_handler)
return logger
我阅读了关于propagate
的文档,并且已经为每个处理程序和logger
显式地将其设置为False
。
当我评估以下内容时...
LOGGER = setup_logger(log_name=LOGGER_NAME)
LEVELS = {"ERROR": logging.ERROR,
"WARNING": logging.WARNING,
"INFO": logging.INFO,
"DEBUG": logging.DEBUG}
for key, value in LEVELS.items():
print(f"################### setLevel : {key}")
LOGGER.setLevel(value)
LOGGER.error("ERROR Message")
LOGGER.warning("WARNING Message")
LOGGER.info("INFO Message")
LOGGER.debug("DEBUG Message")
...它导致LOGGER.error()
被打印四次,LOGGER.warning()
被打印三次,LOGGER.info()
被打印两次,LOGGER.debug()
被打印一次,而不管setLevel
是什么。所以setLevel
的工作原理和我预期的一样,只输出相关级别的消息,但我不明白为什么这些消息会重复。
################### setLevel(ERROR)
I [ERROR : ERROR Message]
D [ERROR : ERROR Message]
E [ERROR : ERROR Message]
W [ERROR : ERROR Message]
################### setLevel(WARNING)
I [ERROR : ERROR Message]
D [ERROR : ERROR Message]
E [ERROR : ERROR Message]
W [ERROR : ERROR Message]
I [WARNING : WARNING Message]
D [WARNING : WARNING Message]
W [WARNING : WARNING Message]
################### setLevel(INFO)
I [ERROR : ERROR Message]
D [ERROR : ERROR Message]
E [ERROR : ERROR Message]
W [ERROR : ERROR Message]
I [WARNING : WARNING Message]
D [WARNING : WARNING Message]
W [WARNING : WARNING Message]
I [INFO : INFO Message]
D [INFO : INFO Message]
################### setLevel(DEBUG)
I [ERROR : ERROR Message]
D [ERROR : ERROR Message]
E [ERROR : ERROR Message]
W [ERROR : ERROR Message]
I [WARNING : WARNING Message]
D [WARNING : WARNING Message]
W [WARNING : WARNING Message]
I [INFO : INFO Message]
D [INFO : INFO Message]
D [DEBUG : DEBUG Message]
编辑:
Python版本为3.10.9
1条答案
按热度按时间4ioopgfo1#
行为符合预期。您有4个处理程序(都写入stdout/stderr)。
根据您的配置,所有处理程序将发出错误级别 LogRecord,其中3个处理程序将发出警告级别 LogRecords......依此类推。
只使用其中一个处理程序(
debug_stream_handler
)。您应该看到预期的结果。