【问题标题】:Python logger always outputting debug messages regardless of filter无论过滤器如何,Python 记录器总是输出调试消息
【发布时间】:2019-06-12 08:42:14
【问题描述】:

我目前正在创建logging.Logger 的子类,它具有基于级别的过滤器,并且此级别可以在日志调用之间更改(因此我使用过滤器而不是setLevel()) .但是,无论过滤器如何,我的记录器似乎总是打印出级别为DEBUG 的消息。下面是我的代码

import logging


class _LevelFilter(logging.Filter):

    def filter(self, record):
        SimpleLogger.setLevel(_DEFAULT_LEVEL)
        return 1 if SimpleLogger.isEnabledFor(record.levelno) else 0


class _SimpleLogger(logging.getLoggerClass()):
    def __init__(self, name=None, level=logging.DEBUG):
        super().__init__(name, level)
        self.setLevel(logging.DEBUG)
        _handler = logging.StreamHandler()
        _handler.setLevel(logging.DEBUG)
        self.addHandler(_handler)
        self.addFilter(_LevelFilter())


_DEFAULT_LEVEL = 'WARNING'
SimpleLogger = _SimpleLogger()

if __name__ == '__main__':
    SimpleLogger.debug('testing debug')
    SimpleLogger.info('testing info')
    SimpleLogger.warning('testing warning')
    SimpleLogger.critical('testing critical')
    SimpleLogger.debug('testing debug')

上面的代码给出以下输出:

testing debug
testing warning
testing critical
testing debug

我知道如果我将SimpleLogger 声明为单独的变量而不是子类,它可以工作,但由于各种原因我需要使用子类。作为参考,这是一个不使用有效子类的版本。

SimpleLogger = logging.getLogger()
SimpleLogger.setLevel(logging.DEBUG)

_handler = logging.StreamHandler()
_handler.setLevel(logging.DEBUG)
SimpleLogger.addHandler(_handler)
SimpleLogger.addFilter(_LevelFilter())

_DEFAULT_LEVEL = 'WARNING'

我终其一生都无法弄清楚为什么总是打印调试消息。子类和非子类版本之间的差异不是很大,设置级别应该会导致调试和信息消息不出现。任何帮助将不胜感激,谢谢!

【问题讨论】:

  • 你的python安装可能有问题,你用的是什么python版本?它适用于最新的python:onlinegdb.com/rkVJ0NA0V
  • 我在 python 3.7.3 中使用 anaconda。
  • 我刚刚尝试重新安装 Anaconda,但仍然得到相同的结果。
  • 好的,另一个更新:我的代码在 python 3.6 中工作,但在 python 3.7 中不工作。但是,似乎在 python 3.7 的日志库中所做的更改不应该影响我的代码。

标签: python-3.x python-logging


【解决方案1】:

我终于找到了解决办法!所以事实证明,python 3.7 向记录器引入了一个缓存,用于缓存 isEnabledFor() 的结果。由于过滤器在初始 isEnabledFor() 检查之后运行,旧的结果仍然被缓存,这导致了这种奇怪的行为。解决方案是不要以这种方式使用过滤器。相反,我真的想要一种替代方法来获得记录器的有效级别。 这里是固定记录器的代码:

编辑:原来我原来的解决方案还是不行,缓存问题依然存在。似乎这是特定于从 logging.getLoggerClass() 子类化的记录器,因此您每次都需要清除缓存。新的解决方案如下。 (另外,我简化了很多,只包含必要的东西。)

class _SimpleLogger(logging.getLoggerClass()):
    def __init__(self, name=None, level=logging.DEBUG):
        super().__init__(name, level)
        _handler = logging.StreamHandler()
        self.addHandler(_handler)

    def isEnabledFor(self, level):
        # Clears logging cache introduced in Python 3.7.
        # Clear here since this is called by all logging methods that write.
        self._cache = {}  # Set instead of calling clear() for compatibility with Python <3.7
        return super().isEnabledFor(level)

# Confirm that this works
if __name__ == "__main__":
    logger = SimpleLogger()
    logger.setLevel(logging.DEBUG)
    # Next 4 logs should print
    logger.debug('d')
    logger.info('i')
    logger.warning('w')
    logger.error('e')

    # Only warning and error logs should print
    logger.setLevel(logging.WARNING)
    logger.debug('d')
    logger.info('i')
    logger.warning('w')
    logger.error('e')

【讨论】:

  • 好收获!您应该接受您的答案作为正确的解决方案,这样您的问题才会得到解决。
  • 不幸的是,我必须等待 2 天才能接受我自己的答案。但是,我会确保这样做!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-22
  • 2020-05-02
  • 2016-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多