[Python-Dev] PEP282 and the warnings framework

Walter Dörwald walter@livinglogic.de
Thu, 16 May 2002 13:44:03 +0200


Kevin Butler wrote:

> [...]
> I don't see how it would work without drastically increasing the 
> configuration complexity.
> 
>     log = logging.getLogger( "pil.image.gif" )
>     log.log( IOError( reason ))
> 
> Currently, I can configure the hierachy pil...image...gif, and I can 
> specify the integer priority level below which I won't log a message in 
> that category.
> 
> If you add the hierarchy 
> IOError...EnvironmentError...StandardError...Exception, how do you 
> decide whether to log the message or not?

The standard module could have the following:

class ClassFilter(Filter):
     def __init__(self, classes, name="")
         super(ClassFilter, self).__init__(name)
         self.classes = classes
     def filter(self, record):
         return isinstance(record, self.classes)

then you could use this filter.

It should be possible to derive from your class LogRecord,
formatting of the message should not be done by Fomatter.format()
which does a record.message = record.msg % record.args, but should
be the responsibility of LogRecord.__str__(), the default implementation
could simply have
     def __str__(self):
         return self.msg % self.args

The constructor for LogRecord should be lightweight enough, so that it
is convenient to create LogRecord instances and pass them to Logger.log
etc. i.e. determining file name and line number should not be the
responsiblity of the function that creates the LogRecord instance,
but the LogRecord constructor.

> - Do you have two separate hierarchies, making each message 
> enabled/disabled for all loggers?  This doesn't seem to give you much 
> flexibility (IOError enabled everywhere).
> 
> - Or does each logger configuration have a hierarchy of message types, 
> and each message type can be enabled/disabled for each logger?  (This 
> seems to require too much configuration.)
> 
> Some other approach I'm not seeing?

The type of the message/log record is simply another property I
can use to filter. And I can extend my filter criteria, because
I'm not tied to the LogRecord instance that gets implicitely
created by Logger.makeRecord. Yes, Logger.makeRecord is documented
as a "factory method", but I couldn't find any possibility to replace
the factory.

>>> FWIW, once you allow logging 'string'-type messages, most logged 
>>> messages will be a string (especially debug messages), because it is 
>>> much easier than creating an instance of some other clsas.  Thus, if 
>>> your categorization is based on the class of the logged message, the 
>>> "string" category gets very large...

So what is different from the current implementation where all messages
are LogRecord instances?

>> NO. Only because a typed message accepts a string in its constructor 
>> does not make it a string. Or since when are all python exceptions in 
>> the 'string' category? 
> 
> 
> If I have a choice between writing:
> 
>   log.debug(
>     "HOME environment variable set to non-existent directory %s",
>     homedir
>     )
> 
> and:
> 
>   log.debug( ConfigurationException(
>     "variable set to non-existent directory",
>     "HOME",
>     homedir
>     ))
> 
> I'm most likely to just use the string option - and
> if I don't have a 'ConfigurationException' class & constructor that exactly
> matches what I need, I'm even more likely to just log the string.

I think the distinction is between
log.log(
     logging.DEBUG,
     "HOME variable set to non-existent directory %s",
     homedir
)
and
log.log(
     ConfigurationException(
      "variable set to non-existent directory",
      "HOME",
      homedir
      )
)

And it would be possible to extend the custom classes with e.g.
localized messages.

 > [...]

Bye,
    Walter Dörwald