Removing handlers from python logs

I play with the Python registration system. I noticed strange behavior when deleting handlers from a Logger object in a loop. Namely, the for for loop removes everything except one handler. An additional call to .removeHandler removes the last handler smoothly. No error messages are generated during calls.

This is the test code:

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

I expect that at the end of the loop, no handlers will remain in the testLogger object, however the last call to .removeHandler does not seem to work, as can be seen from the output below. however, an additional call to this function removes the handler as expected. Here is the result:

 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 

More interestingly, if we replace the original loop with the next, the loop works as expected, and no handlers remain in the testLogger object at the end of the loop. Here is a modified loop:

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

What explains this behavior? Is this a mistake or am I missing something?

+25
python logging
Sep 20 '11 at 11:37
source share
2 answers

It does not depend on the registrar. Never mutate (insert / delete items) the list in which you are currently iterating. If you need, make a copy. In this case, testLogger.handlers = [] should do the trick.

+59
Sep 20 '11 at 11:48
source share

If you do not want to delete them (thanks for the tip of @CatPlusPlus):

 testLogger.handlers = [ h for h in testLogger.handlers if not isinstance(h, logging.StreamHandler)] 
+1
Mar 29 '16 at 18:08
source share



All Articles