Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #68379 > unrolled thread

Clearing out handlers in logging?

Started byTim Chase <python.list@tim.thechases.com>
First post2014-03-15 21:58 -0500
Last post2014-03-16 13:50 -0500
Articles 8 — 4 participants

Back to article view | Back to comp.lang.python


Contents

  Clearing out handlers in logging? Tim Chase <python.list@tim.thechases.com> - 2014-03-15 21:58 -0500
    Re: Clearing out handlers in logging? Gunther Dietrich <gd.usenet@spamfence.net> - 2014-03-16 09:39 +0100
      Re: Clearing out handlers in logging? Chris Angelico <rosuav@gmail.com> - 2014-03-16 20:02 +1100
      Re: Clearing out handlers in logging? Peter Otten <__peter__@web.de> - 2014-03-16 10:18 +0100
      Re: Clearing out handlers in logging? Chris Angelico <rosuav@gmail.com> - 2014-03-16 20:35 +1100
      Re: Clearing out handlers in logging? Tim Chase <python.list@tim.thechases.com> - 2014-03-16 07:57 -0500
        Re: Clearing out handlers in logging? Gunther Dietrich <gd.usenet@spamfence.net> - 2014-03-16 19:29 +0100
          Re: Clearing out handlers in logging? Tim Chase <python.list@tim.thechases.com> - 2014-03-16 13:50 -0500

#68379 — Clearing out handlers in logging?

FromTim Chase <python.list@tim.thechases.com>
Date2014-03-15 21:58 -0500
SubjectClearing out handlers in logging?
Message-ID<mailman.8159.1394938715.18130.python-list@python.org>
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





[toc] | [next] | [standalone]


#68387

FromGunther Dietrich <gd.usenet@spamfence.net>
Date2014-03-16 09:39 +0100
Message-ID<gd.usenet-B1805D.09394016032014@dwarf.main.lan>
In reply to#68379
Tim Chase <python.list@tim.thechases.com> wrote:

>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

>>> dir(log)
['__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:

>>> for handler in log.handlers:
...     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

[toc] | [prev] | [next] | [standalone]


#68388

FromChris Angelico <rosuav@gmail.com>
Date2014-03-16 20:02 +1100
Message-ID<mailman.8163.1394960581.18130.python-list@python.org>
In reply to#68387
On Sun, Mar 16, 2014 at 7:39 PM, Gunther Dietrich
<gd.usenet@spamfence.net> wrote:
>>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:
>
>>>> for handler in log.handlers:
> ...     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

[toc] | [prev] | [next] | [standalone]


#68389

FromPeter Otten <__peter__@web.de>
Date2014-03-16 10:18 +0100
Message-ID<mailman.8164.1394961511.18130.python-list@python.org>
In reply to#68387
Gunther Dietrich wrote:

> Tim Chase <python.list@tim.thechases.com> wrote:
> 
>>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
> 
>>>> dir(log)
> ['__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:
> 
>>>> for handler in log.handlers:
> ...     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?

>>> import logging
>>> logging.basicConfig()
>>> log = logging.getLogger("foo")
>>> for i in range(5):
...     log.addHandler(logging.FileHandler("tmp.log"))
... 
>>> assert len(log.handlers) == 5
>>> for handler in log.handlers:
...     log.removeHandler(handler)
... 
>>> log.handlers
[<logging.FileHandler object at 0x7f8217686e90>, <logging.FileHandler object 
at 0x7f8216f9eb90>]

[toc] | [prev] | [next] | [standalone]


#68390

FromChris Angelico <rosuav@gmail.com>
Date2014-03-16 20:35 +1100
Message-ID<mailman.8165.1394962522.18130.python-list@python.org>
In reply to#68387
On Sun, Mar 16, 2014 at 8:18 PM, Peter Otten <__peter__@web.de> wrote:
> Hm, what do the docs say about this one?
>
>>>> import logging
>>>> logging.basicConfig()
>>>> log = logging.getLogger("foo")
>>>> for i in range(5):
> ...     log.addHandler(logging.FileHandler("tmp.log"))
> ...
>>>> assert len(log.handlers) == 5
>>>> for handler in log.handlers:
> ...     log.removeHandler(handler)
> ...
>>>> log.handlers
> [<logging.FileHandler object at 0x7f8217686e90>, <logging.FileHandler object
> at 0x7f8216f9eb90>]

for handler in log.handlers[:]:
    log.removeHandler(handler)

ChrisA

[toc] | [prev] | [next] | [standalone]


#68393

FromTim Chase <python.list@tim.thechases.com>
Date2014-03-16 07:57 -0500
Message-ID<mailman.8167.1394974663.18130.python-list@python.org>
In reply to#68387
On 2014-03-16 09:39, Gunther Dietrich wrote:
> Tim Chase <python.list@tim.thechases.com> wrote:
> 
> >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.

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

> >>> for handler in log.handlers:
> ...     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





[toc] | [prev] | [next] | [standalone]


#68397

FromGunther Dietrich <gd.usenet@spamfence.net>
Date2014-03-16 19:29 +0100
Message-ID<gd.usenet-EA8AA5.19294616032014@dwarf.main.lan>
In reply to#68393
Tim Chase <python.list@tim.thechases.com> wrote:

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

[toc] | [prev] | [next] | [standalone]


#68399

FromTim Chase <python.list@tim.thechases.com>
Date2014-03-16 13:50 -0500
Message-ID<mailman.8172.1394995811.18130.python-list@python.org>
In reply to#68397
On 2014-03-16 19:29, Gunther Dietrich wrote:
> >> Indeed, THERE IS a removeHandler() method.  
> >
> >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.

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


[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web