Proper way to delete/kill a logger?


C

cassiope

I've been trying to migrate some code to using the standard python
logging classes/objects. And they seem quite capable of doing what I
need them to do. Unfortunately there's a problem in my unit tests.
It's fairly common to have to create quite a few entities in the
course of a series of tests. What appears to be happening is that the
loggers don't get entirely eliminated, so that new invocations end up
spewing output messages from each of the loggers that were started
with this invocation of the python interpreter.

I haven't found a function within the logging module that completely
kills a given instance. The removeHandler() function seems to leave a
stdout/stderr output even if all the assigned handlers have been
removed. I've tried a few workarounds, such as increasing the level
to an absurdly large level, which mostly kinda works, and killing the
old entity before creating the new test version.

There is probably something simple that I'm missing. If you know what
that is, please point me to that fine manual - I'd appreciate it.
Thanks!

-f
 
Ad

Advertisements

C

Chris Withers

I've been trying to migrate some code to using the standard python
logging classes/objects. And they seem quite capable of doing what I
need them to do. Unfortunately there's a problem in my unit tests.
It's fairly common to have to create quite a few entities in the
course of a series of tests. What appears to be happening is that the
loggers don't get entirely eliminated, so that new invocations end up
spewing output messages from each of the loggers that were started
with this invocation of the python interpreter.

Two suggestions:

- unless you are specifically testing the logging set up of your
application, your code under test shouldn't be setting up logging.

- if you want to check that your code under test is emitting log
messages correctly, use a LogCapture from testfixtures:

http://packages.python.org/testfixtures.

cheers,

Chris
 
J

Jean-Michel Pichavant

cassiope said:
I've been trying to migrate some code to using the standard python
logging classes/objects. And they seem quite capable of doing what I
need them to do. Unfortunately there's a problem in my unit tests.
It's fairly common to have to create quite a few entities in the
course of a series of tests. What appears to be happening is that the
loggers don't get entirely eliminated, so that new invocations end up
spewing output messages from each of the loggers that were started
with this invocation of the python interpreter.

I haven't found a function within the logging module that completely
kills a given instance. The removeHandler() function seems to leave a
stdout/stderr output even if all the assigned handlers have been
removed. I've tried a few workarounds, such as increasing the level
to an absurdly large level, which mostly kinda works, and killing the
old entity before creating the new test version.

There is probably something simple that I'm missing. If you know what
that is, please point me to that fine manual - I'd appreciate it.
Thanks!

-f
Loggers are static objects managed by the module itself. When you create
one, it won't be removed until you leave the shell. Thas is way it is
advise not to create thousands of loggers with different names.
That's the module design, nothing you can do about it.

It takes a little time to get used to it but the logging documentation
has a lot of examples showing how to use to module.
Your main problem is that some of your test instances are configuring
the loggers, they should not. Configuration should be done in the 'main'
function *only*.

import logging, sys

class Test1:
def __init__(self):
self.logger = logging.getLogger(self.__class__.__name__) #
create a new logger or reuse one if a logger with that name already exists
self.logger.info('I am created')
# adding a handler to the logger here would be a mistake,
configuration is let to the user, in this case the program main entry point
# objects raising log events should not care about how they are
formated/displayed
class Test2:
def __init__(self):
self.logger = logging.getLogger(self.__class__.__name__)
self.logger.info('I am created')

def main():
# configure here the logger, usually the root logger
root = logging.getLogger()
root.handlers = [] # required if you don't want to exit the shell
between 2 executions (not very wise)
root.setLevel(logging.DEBUG)
root.addHandler(logging.StreamHandler(sys.stdout))
root.handlers[-1].setFormatter(logging.Formatter('%(name)s -
%(levelname)s - %(message)s'))

t1 = Test1()
t2 = Test2()
t3 = Test2()

if __name__ == '__main__':
main()
run test.py
Test1 - INFO - I am created
Test2 - INFO - I am created
Test2 - INFO - I am created


JM

PS : one way to cleanup a logger is to remove all its handlers, i.e.
logger.handlers = [], but if you need to do this you may have done
something wrong.
 
R

Roy Smith

Jean-Michel Pichavant said:
Loggers are static objects managed by the module itself.

For reasons I can't quite explain, that sentence makes me want to sing
The Lumberjack Song. "I'm a logger(*) and I'm OK..."

(*) Yes, I know that's not right.
 
Ad

Advertisements

C

cassiope

Thanks Chris and JM, I will explore how much work it's going to take
to change the various scripts to _always_ starting the logger from
main().
As further explanation - this code predates the logging module, and
many of the functions/classes had an optional argument for the home-
made
logger - and where the caller didn't provide it, it was locally
created.
The unit tests were carefully enough put together to provide almost
complete coverage, resulting in creating the logger possibly a dozen
or more times in the course of the tests.

So I appreciate what "doing it the right way" means, I was just hoping
not to have to go there, as I have a lot of code that uses the old
structures. It makes it harder to justify moving to the "newer"
module.

I'll have to try the logger.handlers=[] approach, thanks.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top