重复的日志输出,但没有重复的处理程序
Duplicate log output, but no duplicate handlers
我从一个只附加了 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')
记录器 propagate 默认将事件记录到其祖先的处理程序中。 a_logger
可能只有一个处理程序,但它的父级,即根记录器,也有一个处理程序(实际上是同一个处理程序)。 a_logger.info('hi')
由两个处理程序处理(实际上是同一个处理程序两次)。
您不需要将相同的处理程序附加到每个记录器。将它附加到根记录器就足够了。
我从一个只附加了 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')
记录器 propagate 默认将事件记录到其祖先的处理程序中。 a_logger
可能只有一个处理程序,但它的父级,即根记录器,也有一个处理程序(实际上是同一个处理程序)。 a_logger.info('hi')
由两个处理程序处理(实际上是同一个处理程序两次)。
您不需要将相同的处理程序附加到每个记录器。将它附加到根记录器就足够了。