子记录器的日志显示两次

时间:2017-09-21 06:51:34

标签: python python-3.x logging

我无法使用python的标准logging正确记录我的模块。然而,这是一个非常简单的案例。 我有以下模块层次结构:

module\
  foo.py
  bar.py

我需要使用以下约束来记录每个模块:

  1. INFO到控制台的所有日志> = module.foo(因为此模块的功能很重要,用户必须现场通知)
  2. module.*到文件的所有日志
  3. 所有日志> = WARNINGmodule.*到控制台
  4. 这是主要代码

    import logging
    import logging.config
    import os
    import yaml
    
    def setup_logging():
        loadfrom = os.path.join(os.path.dirname(__file__), 'config.yml')
        # Load
        with open(loadfrom, 'rt') as f:
            config = yaml.safe_load(f.read())
        logging.config.dictConfig(config)
    
    setup_logging()
    
    foo = logging.getLogger('module.foo')
    bar = logging.getLogger('module.bar')
    
    foo.info('module.foo doing something')
    foo.debug('module.foo debug data')
    
    bar.info('module.bar doing something')
    bar.error('module.bar something bad happened')
    

    以下是我使用

    的配置
    version: 1
    disable_existing_loggers: False
    formatters:
        simple:
            format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
    
    handlers:
        console:
            class: logging.StreamHandler
            level: INFO
            formatter: simple
            stream: ext://sys.stdout
        file:
            class: logging.handlers.RotatingFileHandler
            level: DEBUG
            filename: 'log.log'
            formatter: simple
            encoding: utf8
    
    loggers:
      module:
        level: WARNING
        handlers: [console]
        propagate: yes
      module.foo:
        level: INFO
        handlers: [console]
        propagate: yes # If yes, gets displayed twice. If false, entry is missing in log file
    root:
        level: DEBUG
        handlers: [file]
    

    这是输出:

    2017-09-21 10:48:39,679 - module.foo - INFO - module.foo doing something
    2017-09-21 10:48:39,679 - module.foo - INFO - module.foo doing something
    2017-09-21 10:48:39,681 - module.bar - ERROR - module.bar something bad happened
    

    子模块中的log.info显示两次,因为配置中propagate字段设置为yes。 将其设置为false可解决控制台中的问题但会中断日志文件,因为其中缺少该条目。

    我该如何解决这个问题?标准库的任何替代品,我个人认为违反直觉?

    编辑1

    @ wmorell回答后的新配置:

    handlers:
        console:
            class: logging.StreamHandler
            level: INFO
            formatter: simple
            stream: ext://sys.stdout
        file:
            class: logging.handlers.RotatingFileHandler
            level: DEBUG
            filename: 'log.log'
            formatter: simple
            encoding: utf8
    
    loggers:
      module:
        level: WARNING
        handlers: [console]
        propagate: yes
      module.foo:
        level: DEBUG    <- set this to debug
        handlers: [file, console] <- Add file here
        propagate: false
    root:
        level: DEBUG
        handlers: [file]
    

    控制台输出正常:

    2017-09-21 11:14:51,174 - module.foo - INFO - module.foo doing something
    2017-09-21 11:14:51,174 - module.bar - ERROR - module.bar something bad happened
    

    日志输出不正常,错过了对log.info('module.bar')的调用:

    2017-09-21 11:18:34,335 - module.foo - INFO - module.foo doing something
    2017-09-21 11:18:34,335 - module.foo - DEBUG - module.foo debug data
    2017-09-21 11:18:34,335 - module.bar - ERROR - module.bar something bad happened
    

1 个答案:

答案 0 :(得分:1)

file处理程序显式添加到记录器定义,然后复制console处理程序以过滤掉不同的日志级别:

handlers:
  console_info:
    class: logging.StreamHandler
    level: INFO
    formatter: simple
    stream: ext://sys.stdout
  console_warning:
    class: logging.StreamHandler
    level: WARNING
    formatter: simple
    stream: ext://sys.stdout
  file:
    class: logging.handlers.RotatingFileHandler
    level: DEBUG
    filename: 'log.log'
    formatter: simple
    encoding: utf8
loggers:
  module:
    level: DEBUG
    handlers: [file, console_warning]
    propagate: false
  module.foo:
    level: DEBUG
    handlers: [file, console_info]
    propagate: false

首先在记录器定义中对日志进行过滤,因此modulemodule.foo记录器必须允许DEBUG,如果要将其记录到日志文件中。记录器然后将消息转发给所有处理程序,处理程序可以将消息丢弃到其配置的阈值以下;因此,您需要一个处理程序,它将删除基本INFO记录器的module日志,以及一个允许INFO日志记录更具体的module.foo记录器的处理程序。