This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: logging handlers raise exception on level
Type: Stage:
Components: Library (Lib) Versions: Python 2.3
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: vinay.sajip Nosy List: Mickey.Killianey, jimjjewett, vinay.sajip
Priority: normal Keywords:

Created on 2004-01-13 22:04 by jimjjewett, last changed 2022-04-11 14:56 by admin. This issue is now closed.

Messages (10)
msg19675 - (view) Author: Jim Jewett (jimjjewett) Date: 2004-01-13 22:04
logging.__version__ = "0.4.8.1" - matches CVS

Handler() takes a keyword argument of level, for the 
initial level of message it should care about.

StreamHandler inherits from Handler, but does not pass 
the level keyword through when calling Handler__init__.

    #def __init__(self, strm=None):
    def __init__(self, strm=None, **kwargs):

         #Handler.__init__(self)
         # should we delete the key that Stream uses?
         Handler.__init__(self, **kwargs)


I am submitting as a bug rather than a patch because 
several other classes have the same problem, and 
because I am not sure whether arguments used by the 
child initializer (such as strm) should be passed on.


msg19676 - (view) Author: Vinay Sajip (vinay.sajip) * (Python committer) Date: 2004-01-18 19:02
Logged In: YES 
user_id=308438

I don't think this is a bug. You should consider that 
Handler.__init__() takes a level argument with a default 
value, rather than a keyword argument. This should be 
treated as an internal implementation detail, used only by 
subclasses of Handler. If you are writing a Handler subclass, 
you can pass the level argument via your 
HandlerSubclass.__init__() to Handler.__init__(). Otherwise, 
you can set the level using Handler.setLevel().
msg19677 - (view) Author: Jim Jewett (jimjjewett) Date: 2004-01-19 17:57
Logged In: YES 
user_id=764593

In general, it seems odd that Class(arg=val) would work, but 
subClass(arg=val) would fail, unless subclass is designed 
explicitly to restrict capabilities.  

logfile = logging.Handler(level=logging.ERROR) works.[1]  

logfile = logging.StreamHandler(level=logging.ERROR) fails, even 
though the level is still relevant and reasonable.

If I submit a patch for the classes distributed with the library, 
would it be an acceptable change?

[1] Admittedly, this handler might fail later, because Handler.
emit() assumes that Handler is abstract.
msg19678 - (view) Author: Vinay Sajip (vinay.sajip) * (Python committer) Date: 2004-01-22 23:19
Logged In: YES 
user_id=308438

It's not really odd that Class(arg=val) would work, but 
subClass(arg=val) would fail. This is because there is no 
requirement that base class constructors and derived class 
constructors need to look the same. Of course, the derived 
class needs to understand how to construct the base class.

Please note that the Handler class is a base class, not 
intended to be instantiated - as you know. So your example is 
not really valid.

Please don't submit a patch for this, it's not a bug. I still don't 
understand why you can't use setLevel() to set your level. 
Why does it *have* to be in the constructor?
msg19679 - (view) Author: Jim Jewett (jimjjewett) Date: 2004-01-23 22:23
Logged In: YES 
user_id=764593

One reason to use a standard library is so that my own code 
won't have to worry about any more detail than I want to -- I 
shouldn't even have to read the code within the library for 
implementation details.  

The more study required/glue code needed/state I must keep, 
the less useful the library is.  Keeping a reference and using 
setLevel is a workaround, but it should not be required.  I 
should be able to set up a handler in one line.  For example, to 
log everything and echo important stuff to the user:

logging.addHandler(StreamHandler(level=ERROR))
logging.addHandler(RotatingFileHandler("mylog",level=DEBUG))

(note that the level=DEBUG is only required because the 
default of 0 really turns into WARNING if I don't reset it.)
msg19680 - (view) Author: Vinay Sajip (vinay.sajip) * (Python committer) Date: 2004-01-23 22:53
Logged In: YES 
user_id=308438

I'm sorry if you don't find the library very useful. I don't 
regard using setLevel() as a workaround - it was designed 
this way. Not all designers would design things the same way. 
You are the first and only person to raise this issue, after 
many months during which the library has been in use (even 
before Python 2.3 was released). If many people raise this as 
an issue, I will have to rethink this - but right now I don't 
think making a change is justified. I certainly haven't 
regarded the "set up a hander in one line" as a design goal. If 
you use a configuration file, you can set up multiple handlers, 
formatters and loggers in just one or two lines of code. (Not 
that I am recommending using a configuration file - but the 
functionality is there).

Thanks for taking the time to put your point of view, though. 
I genuinely appreciate it.
msg109484 - (view) Author: Mickey Killianey (Mickey.Killianey) Date: 2010-07-07 17:02
Would you be willing to consider supporting the level keyword as a convenience for the most simple/common Handlers?  (For example, maybe just StreamHandler and FileHandler?)
msg109836 - (view) Author: Vinay Sajip (vinay.sajip) * (Python committer) Date: 2010-07-10 09:00
If I did this for some but not handler classes, then people would probably log issues saying e.g. "Why doesn't NTEventLogHandler" support a level argument? Other handlers do." etc.

What's the big problem with using setLevel() to set the level? If you're after convenience, you could use the dictionary configuration API which allows you to set the levels declaratively.
msg110162 - (view) Author: Mickey Killianey (Mickey.Killianey) Date: 2010-07-13 09:01
Vinay:  thanks for the response.

My use case is that I've inherited a legacy application with a problematic third-party module (call it 'foo').  I want to sprinkle in some file-logging for the 'foo' logger to trace what's going on, while making the minimal impact on the module.  Since 'foo' does some reflection on itself, I also want to avoid introducing new symbols in the module, if possible.

You said:

> If you're after convenience, you could use the dictionary 
> configuration API which allows you to set the levels 
> declaratively.

If by "dictionary configuration API" you're suggesting logging.config.dictConfig, then yes, it does meet my criteria, although the minimal amount of code to configure one file handler looks pretty long-winded for what seems like a fairly common request:

  logging.config.dictConfig({
      'version' : 1,
      'handlers' : {
        'handler_name' : { 
          'class' : 'logging.FileHandler',
          'level' : logging.DEBUG,
          'filename' : 'foo.log',
        },
      },
      'loggers' : {
        'foo' : {
          'handlers' : [
            'handler_name',
          ],
        },
      },
    })

Or were you suggesting logging.basicConfig?  The limitation of basicConfig seems to be that it only works on an unconfigured root logger, not on a named logger, and it doesn't work if anyone else has touched root.

I was hoping for something that's simple, easy-to-remember, easy-to-type, and makes a minimal impact on the module I'm debugging.  For example, how do any of these sound...?

...if basicConfig had an optional 'name' argument, so that it could config loggers other than root logger:

  logging.basicConfig(name='foo', filename='foo.log', level=DEBUG)

...if 'basicConfig' was a method on Logger:

  logging.getLogger('foo').basicConfig(filename='foo.log', level=DEBUG)

...if the handlers' setters supported the builder pattern and returned self from setLevel:

  logging.getLogger('foo').addHandler(FileHandler('foo.log').setLevel(DEBUG))


(Instead of commenting on this closed bug, should I enter this as a new issue and set it as a feature request?)
msg110200 - (view) Author: Vinay Sajip (vinay.sajip) * (Python committer) Date: 2010-07-13 14:54
----- Original Message ----

> Mickey Killianey <mickey.killianey@gmail.com>  added the comment:
> 
> Or were you suggesting logging.basicConfig?  The limitation of  basicConfig 
>seems to be that it only works on an unconfigured root logger, not  on a named 
>logger, and it doesn't work if anyone else has touched root.

True, but if you use basicConfig to configure the root logger, descendant 
loggers (such as 'foo') will use those handlers. Of course, if someone else has 
configured a handler for the root logger already, then you may not be able to 
use this.

> 
> I  was hoping for something that's simple, easy-to-remember, easy-to-type, and  
>makes a minimal impact on the module I'm debugging.  For example, how do  any of 
>these sound...?
> 
> ...if basicConfig had an optional 'name' argument,  so that it could config 
>loggers other than root logger:
> 
>    logging.basicConfig(name='foo', filename='foo.log', level=DEBUG)
> 
> ...if  'basicConfig' was a method on Logger:
> 
>    logging.getLogger('foo').basicConfig(filename='foo.log',  level=DEBUG)
> 
> ...if the handlers' setters supported the builder pattern  and returned self 
>from setLevel:
> 
>    logging.getLogger('foo').addHandler(FileHandler('foo.log').setLevel(DEBUG))
> 
> 
> (Instead  of commenting on this closed bug, should I enter this as a new issue 
>and set it  as a feature  request?)
> 

I'd like to avoid making the kinds of changes which are stylistic in nature; the 
existing APIs will need to remain for backward compatiblity reasons, and I don't 
want to add the same functionality using different idioms based on what are 
essentially stylistic preferences. Also, remember that Python 2.x is essentially 
frozen in terms of new releases (as 2.7 has been released and no 2.8 is planned) 
so any API changes would apply to 3.2 and later only - I'm guessing you're still 
on Python 2.x if you're using a legacy application.

When all's said and done, to configure a logger for 'foo' with a FileHandler and 
a specific level will not require more than a few lines of code, so I'd just go 
ahead and code them up and not worry about trying to get the whole thing to fit 
on a single line :-)

Regards,

Vinay Sajip

.
History
Date User Action Args
2022-04-11 14:56:02adminsetgithub: 39817
2010-07-13 14:54:42vinay.sajipsetmessages: + msg110200
2010-07-13 09:01:49Mickey.Killianeysetmessages: + msg110162
2010-07-10 09:00:54vinay.sajipsetmessages: + msg109836
2010-07-07 17:02:12Mickey.Killianeysetnosy: + Mickey.Killianey
messages: + msg109484
2004-01-13 22:04:55jimjjewettcreate