从Python的日志记录器中移除处理器
我在玩Python的日志系统时,发现了一个奇怪的现象。在一个循环中从Logger对象中移除处理器时,发现我的循环只移除了所有处理器中的一个,最后一个处理器在调用.removeHandler
时可以顺利移除。在这个过程中没有出现任何错误信息。
这是我的测试代码:
import logging
import sys
logging.basicConfig()
dbg = logging.getLogger('dbg')
dbg.setLevel(logging.DEBUG)
testLogger = logging.getLogger('mylogger')
sh = logging.StreamHandler(sys.stdout)
fh = logging.FileHandler('mylogfile.log')
dbg.debug('before adding handlers: %d handlers'%len(testLogger.handlers))
testLogger.addHandler(fh)
testLogger.addHandler(sh)
dbg.debug('before removing. %d handlers: %s'%(len(testLogger.handlers),
str(testLogger.handlers)))
for h in testLogger.handlers:
dbg.debug('removing handler %s'%str(h))
testLogger.removeHandler(h)
dbg.debug('%d more to go'%len(testLogger.handlers))
#HERE I EXPECT THAT NO HANDLER WILL REMAIN
dbg.debug('after removing: %d handlers: %s'%(len(testLogger.handlers),
str(testLogger.handlers)))
if len(testLogger.handlers) > 0:
#Why is this happening?
testLogger.removeHandler(testLogger.handlers[0])
dbg.debug('after manually removing the last handler: %d handlers'%len(testLogger.handlers))
我本来期望在循环结束时,testLogger
对象里没有任何处理器,但最后一次调用.removeHandler
似乎没有成功,从下面的输出可以看出来。不过,额外再调用一次这个函数时,处理器就如预期一样被移除了。以下是输出结果:
DEBUG:dbg:before adding handlers: 0 handlers
DEBUG:dbg:before removing. 2 handlers: [<logging.FileHandler instance at 0x021263F0>, <logging.StreamHandler instance at 0x021262B0>]
DEBUG:dbg:removing handler <logging.FileHandler instance at 0x021263F0>
DEBUG:dbg:1 more to go
DEBUG:dbg:after removing: 1 handlers: [<logging.StreamHandler instance at 0x021262B0>]
DEBUG:dbg:after manually removing the last handler: 0 handlers
更有趣的是,如果我把原来的循环替换成下面这个,循环就能正常工作,循环结束时testLogger
对象里不会剩下任何处理器。这里是修改后的循环:
while len(testLogger.handlers) > 0:
h = testLogger.handlers[0]
dbg.debug('removing handler %s'%str(h))
testLogger.removeHandler(h)
dbg.debug('%d more to go'%len(testLogger.handlers))
这是什么原因造成的呢?这是个bug,还是我漏掉了什么?
5 个回答
18
如果你不想把它们全部删除(感谢这个建议和@CatPlusPlus):
testLogger.handlers = [
h for h in testLogger.handlers if not isinstance(h, logging.StreamHandler)]
24
不要直接修改那些没有文档说明的 .handler
:
选项 1
logging.getLogger().removeHandler(logging.getLogger().handlers[0])
这样你可以通过官方的方式准确地移除已经存在的处理程序对象。或者,你也可以移除所有的处理程序:
logger = logging.getLogger()
while logger.hasHandlers():
logger.removeHandler(logger.handlers[0])
选项 2
logging.config.dictConfig(config={'level': logging.DEBUG, 'handlers': []})
这个方法不仅可以移除处理程序,还能防止它的创建。这样列表的根部就会有 []
这个空的处理程序。
162
这不是特定于日志记录器的行为。绝对不要在你正在遍历的列表上进行修改(比如插入或删除元素)。如果需要修改,最好先复制一份。在这种情况下,使用 testLogger.handlers.clear()
就可以解决问题。