Clearing out handlers in logging?

T

Tim Chase

The current (2.7; maybe 3.x?) logging module doesn't have any sort of
"clear out all the current handlers" method. I can hack it by doing

log = logging.getLogger() # get the root logger
del log.handlers[:] # reach inside and nuke 'em
log.addHandler(...) # install the one(s) I want

but it feels a little dirty to reach into logging.root.handlers since
there are other methods for adding/removing handlers. However, as
best I can tell, to remove a handler, you already need to have it
saved somewhere.

Is there a better way to do this, or do I just suck it up and deal
with the (potentially thread-ignorant, as it doesn't lock) hack?

Thanks,

-tkc
 
G

Gunther Dietrich

Tim Chase said:
The current (2.7; maybe 3.x?) logging module doesn't have any sort of
"clear out all the current handlers" method.

Indeed, THERE IS a removeHandler() method. In the documentation of
python 2.6, it is mentioned in '16.6.5. Logger Objects', directly after
the addHandler() method. If you found the addHandler() method there, you
should have found removeHandler() too.

And a simple
['__doc__', '__init__', '__module__', '_log', 'addFilter', 'addHandler',
'callHandlers', 'critical', 'debug', 'disabled', 'error', 'exception',
'fatal', 'filter', 'filters', 'findCaller', 'getEffectiveLevel',
'handle', 'handlers', 'info', 'isEnabledFor', 'level', 'log',
'makeRecord', 'manager', 'name', 'parent', 'propagate', 'removeFilter',
'removeHandler', 'root', 'setLevel', 'warn', 'warning']

also would have revealed it to you.

I can hack it by doing

log = logging.getLogger() # get the root logger
del log.handlers[:] # reach inside and nuke 'em
log.addHandler(...) # install the one(s) I want

but it feels a little dirty to reach into logging.root.handlers since
there are other methods for adding/removing handlers. However, as
best I can tell, to remove a handler, you already need to have it
saved somewhere.

What about this:
.... log.removeHandler(handler)

I think, that's just one of the tasks that removeHandler() was written
for.

Is there a better way to do this, or do I just suck it up and deal
with the (potentially thread-ignorant, as it doesn't lock) hack?

One of the best ways would be to read the documentation. And to do some
exploration, e.g. by means of dir() and help(), could also be quite
instructive. This experience cannot be replaced by
documentation-research requests to the Usenet.



Best regards,

Gunther
 
C

Chris Angelico

What about this:

... log.removeHandler(handler)

I think, that's just one of the tasks that removeHandler() was written
for.

I'm sure Tim was aware of the removeHandler function. But this is
still reaching into log.handlers - although IMO it's safer to reach in
and read than to reach in and mutate. So without the implications of
Tim's inability to read docs, this is a viable suggestion. I'd prefer
this over the original "del log.handlers[:]".

ChrisA
 
P

Peter Otten

Gunther said:
Tim Chase said:
The current (2.7; maybe 3.x?) logging module doesn't have any sort of
"clear out all the current handlers" method.

Indeed, THERE IS a removeHandler() method. In the documentation of
python 2.6, it is mentioned in '16.6.5. Logger Objects', directly after
the addHandler() method. If you found the addHandler() method there, you
should have found removeHandler() too.

And a simple
['__doc__', '__init__', '__module__', '_log', 'addFilter', 'addHandler',
'callHandlers', 'critical', 'debug', 'disabled', 'error', 'exception',
'fatal', 'filter', 'filters', 'findCaller', 'getEffectiveLevel',
'handle', 'handlers', 'info', 'isEnabledFor', 'level', 'log',
'makeRecord', 'manager', 'name', 'parent', 'propagate', 'removeFilter',
'removeHandler', 'root', 'setLevel', 'warn', 'warning']

also would have revealed it to you.

I can hack it by doing

log = logging.getLogger() # get the root logger
del log.handlers[:] # reach inside and nuke 'em
log.addHandler(...) # install the one(s) I want

but it feels a little dirty to reach into logging.root.handlers since
there are other methods for adding/removing handlers. However, as
best I can tell, to remove a handler, you already need to have it
saved somewhere.

What about this:
... log.removeHandler(handler)

I think, that's just one of the tasks that removeHandler() was written
for.

Is there a better way to do this, or do I just suck it up and deal
with the (potentially thread-ignorant, as it doesn't lock) hack?

One of the best ways would be to read the documentation. And to do some
exploration, e.g. by means of dir() and help(), could also be quite
instructive. This experience cannot be replaced by
documentation-research requests to the Usenet.

Hm, what do the docs say about this one?
.... log.addHandler(logging.FileHandler("tmp.log"))
........ log.removeHandler(handler)
....[<logging.FileHandler object at 0x7f8217686e90>, <logging.FileHandler object
at 0x7f8216f9eb90>]
 
T

Tim Chase

Indeed, THERE IS a removeHandler() method.

Yes, I'm aware of it, having read the source & docs. However, the
signature is

removeHandler(some_handle_to_a_handler_that_you_already_have)

and at the point in my code where I need to override this,
basicConfig() has already assigned a default stream handler and
discarded the handle/name/reference to it because
the .debug/.info/.warn/.error/.critical methods of all call
basicConfig() if there aren't any handlers.

[Aside: which is non-pythonically, using "if len(self.handlers) == 0"
instead of "if not self.handlers" in addition to the camel-case
naming (which would be much harder to fix)]
... log.removeHandler(handler)

I think, that's just one of the tasks that removeHandler() was
written for.

The question revolves mostly around dipping your hands into the
undocumented .handlers property. I can nuke it directly (and looking
at least at the 2.7 source, there doesn't seem to be much issue with
doing this), or I can iterate (as modified by Chris Angelico to
prevent modifying the list over which you're iterating). Either way,
it still involves reaching into log.handlers which doesn't appear in
any of the documentation as far as I could find.

So yes, I use help() and dir() on a daily basis. But just because
something is there doesn't mean I should go mucking with it in the
event it's undocumented. If it *should* be trusted as a publicly
available interface, it should be documented; if it shouldn't be
treated publicly, then it should have a way to iterate over them
such as

def iterHandlers(self):
for h in self.handlers[:]:
yield h

so you can do

for h in log.iterHandlers():
log.removeHandler(h)

Given how stable this code has been over the years, I'd just document
the log.handlers property and possibly advise to lock around messing
with it (unless "del log.handlers[:]" is atomic).

-tkc
 
G

Gunther Dietrich

Tim Chase said:
Yes, I'm aware of it, having read the source & docs. However, the
signature is

Sorry, your original article lacks information about what you already
know/tried and what not. So it is a bit misleading and makes the
impression, you would't read the documentation. It would have been
helpful if you had told us your preconditions.



Best regards,

Gunther
 
T

Tim Chase

Sorry, your original article lacks information about what you
already know/tried and what not. So it is a bit misleading and
makes the impression, you would't read the documentation. It would
have been helpful if you had told us your preconditions.

Heh, I tried to make that clear in my initial posting with the "since
there are other methods for adding/removing handlers" bit. I guess I
could have been more explicit though as to what I'd tried. I
generally figure that, if someone knows enough to dig into the
stdlib's source code, they also know enough to use dir() and help().
Not *always* the case, but a good hint that they're past the basics.

But I could have clarified my question more along the lines of
"Should log.handlers be public/documented; should Logger grow
clearHandlers() and iterHandlers() methods; or should I wantonly use
log.handlers but then just get to keep both pieces if/when it breaks?"

-tkc
 

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

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,062
Latest member
OrderKetozenseACV

Latest Threads

Top