Python 无论过滤器如何,记录器始终输出调试消息
Python logger always outputting debug messages regardless of filter
我目前正在创建 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 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')
我目前正在创建 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 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')