繁体   English   中英

从 python 的日志记录器中删除处理程序

[英]Removing handlers from python's logging loggers

我正在玩 Python 的日志记录系统。 在循环中从 Logger object 中删除处理程序时,我注意到了一个奇怪的行为。 也就是说,我的 for 循环删除了除一个处理程序之外的所有处理程序。 .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 object 中不会保留任何处理程序,但是最后一次调用.removeHandler显然失败了,从下面的 output 可以看出。 尽管如此,对这个 function 的额外调用会按预期删除处理程序。 这是 output:

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 object 中不会保留任何处理程序。 这是修改后的循环:

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))

什么解释了这种行为? 这是一个错误还是我错过了什么?

这不是特定于记录器的行为。 永远不要改变(插入/删除元素)您当前正在迭代的列表。 如果需要,请复印一份。 在这种情况下, testLogger.handlers = []应该可以解决问题。

如果您不想全部删除它们(感谢提示@CatPlusPlus ):

testLogger.handlers = [
    h for h in testLogger.handlers if not isinstance(h, logging.StreamHandler)]

而不是改变未记录的.handler

选项1

logging.getLogger().removeHandler(logging.getLogger().handlers[0])

通过这种方式,您可以通过官方 api 完全删除预先存在的处理程序对象。 或者删除所有处理程序:

logger = logging.getLogger()
while logger.hasHandlers():
    logger.removeHandler(logger.handlers[0])

选项 2

logging.config.dictConfig(config={'level': logging.DEBUG, 'handlers': []}

不仅删除而且阻止它的创建。 列表根将有[]处理程序

我会说,如果删除日志处理程序的目的是防止将日志发送到其他处理程序(大多数情况下都是这种情况),那么我遵循的另一种方法是将当前记录器的propagate设置为False

logger = logging.getLogger(__name__)
logger.propagate = False

这样,您的日志消息将仅 go 到您明确添加的处理程序,并且不会传播到父记录器。

我刚刚发现您也可以在日志记录 .ini 文件中使用以下块执行此操作:

[logger_stpipe]
handlers=
propagate=1
qualname=stpipe

它基本上停用给定记录器的所有处理程序。 但它有一定的局限性,因为您必须提前知道 Logger 的名称。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM