【问题标题】:Duplicate log output, but no duplicate handlers重复的日志输出,但没有重复的处理程序
【发布时间】:2019-06-24 02:46:13
【问题描述】:

我从一个仅附加了 1 个处理程序的记录器获得重复的日志输出。

如何调试?

代码(应该可以复制粘贴):

import io
import logging
import os
import sys
from typing import Optional


DEFAULT_LOG_LEVEL = logging.INFO


def get_sub_loggers():
    return [
        logging.getLogger('a'),
        logging.getLogger('b'),
        logging.getLogger('c')
    ]


def safe_add_handler(logger: logging.Logger, h: logging.Handler) -> None:
    if h not in logger.handlers:
        logger.addHandler(h)


def safe_add_filter(logger: logging.Logger, f: logging.Filter) -> None:
    if f not in logger.filters:
        logger.addFilter(f)


def configure_logging(main_logger: logging.Logger,
                      log_level = DEFAULT_LOG_LEVEL,
                      log_file = None,
                      fmt: Optional[str] = None,
                      force_add_handler: bool = False) -> None:
    main_logger.setLevel(log_level)
    logging.captureWarnings(True)  # send all warnings to be logged

    if force_add_handler or not main_logger.hasHandlers():
        if log_file is None or log_file == '-':
            log_file = sys.stderr

        if isinstance(log_file, (str, os.PathLike)):
            handler = logging.FileHandler(log_file)
        else:
            handler = logging.StreamHandler(log_file)

        handler.setFormatter(logging.Formatter(fmt if fmt is not None else logging.BASIC_FORMAT))

        main_logger.addHandler(handler)
        log_output_location = handler.stream.name if isinstance(handler, logging.StreamHandler) else handler.baseFilename
        main_logger.info('Writing logs to {}'.format(log_output_location))
    else:
        main_logger.info('Using existing log handlers')

    main_logger.info('Using log level {}'.format(log_level))

    for logger in get_sub_loggers():
        logger.setLevel(log_level)
        for h in main_logger.handlers:
            safe_add_handler(logger, h)
        for f in main_logger.filters:
            safe_add_filter(logger, f)
        main_logger.debug('Configured logger {}'.format(logger.name))

    main_logger.info('Configured submodule loggers.')


configure_logging(logging.getLogger())

a_logger = logging.getLogger('a')
assert len(a_logger.handlers) == 1

# Should only output "hi" once, but it does it twice
a_logger.info('hi')

【问题讨论】:

  • 为什么要向四个记录器添加相同的处理程序?

标签: python python-3.x logging python-logging


【解决方案1】:

默认情况下,记录器propagate 将事件记录到其祖先的处理程序。 a_logger 可能只有一个处理程序,但它的父级根记录器也有一个处理程序(实际上是同一个处理程序)。 a_logger.info('hi') 由两个处理程序处理(实际上是同一个处理程序两次)。

您不需要将相同的处理程序附加到每个记录器。将它附加到根记录器就足够了。

【讨论】:

  • 我明白了,所以除了检查记录器本身之外,我还需要检查子记录器的父母是否有处理程序?
  • @shadowtalker:您不需要手动将处理程序附加到每个记录器。您将其附加到根记录器。够了。
  • 此代码将用于除根记录器(可能不是任何子记录器的父级)以外的记录器。
  • @shadowtalker:你是说根记录器可能不是任何子记录器的父级吗?根记录器是所有其他记录器的祖先。如果您说根记录器可能不是您将处理程序添加到的记录器之一,那么您将遇到问题,例如当您将处理程序添加到记录器之后添加时会发生什么该处理程序到该记录器的后代。
  • @shadowtalker:我不知道。无论哪种方式都有问题。 (总的来说,我真的不喜欢logging 模块设计。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-09-28
  • 2018-12-16
  • 1970-01-01
  • 1970-01-01
  • 2016-12-22
  • 2012-08-03
  • 1970-01-01
相关资源
最近更新 更多