python 日志处理程序传播问题-消息重复

mnemlml8  于 2023-01-19  发布在  Python
关注(0)|答案(1)|浏览(105)

我试图为一个模块设置日志记录,并有以下最小的可复制的例子...

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

4ioopgfo

4ioopgfo1#

行为符合预期。您有4个处理程序(都写入stdout/stderr)。
根据您的配置,所有处理程序将发出错误级别 LogRecord,其中3个处理程序将发出警告级别 LogRecords......依此类推。
只使用其中一个处理程序(debug_stream_handler)。您应该看到预期的结果。

相关问题