[Python-Dev] PEP282 and the warnings framework

Kevin Butler kbutler@campuspipeline.com
Wed, 15 May 2002 09:51:26 -0600

<walter@livinglogic.de> wrote:
> And looking at the warning framework suggests a different way
> of handling log levels/types: Instead of specifying types
> with integer constants and configuring what to log with a
> threshold value, we could have a class hierarchy of message
> types similar to the hierarchy for warning types:
> class Message(Exeption):
>      pass
> class InfoMessage(Message):
>      pass
> class ErrorMessage(InfoMessage):
>      pass
> class FatalMessage(ErrorMessage):
>      pass
> This hierarchy is customizable with user defined classes:
> class ResourceMessage(FatalMessage):
>      pass
> class DiskFullMessage(ResourceMessage):
>      pass
> class OutOfMemoryMessage(ResourceMessage):
>      pass

We could, but it would be a mistake.  :-)

Subclasses should differ in behavior - if they differ only in data, that data 
should go into attributes instead. (Yes, this is disputable, but it does tend 
to simplify designs.)

The Info/Error/Fatal classes differ only in name (with the name mapping to a 
'severity'), making it more appropriate for them to be distinguished by some 
sort of 'severity' attribute. Similarly for the message subclasses (with a 
name mapping to 'message type').

Having struggled with a message-hierarchy-based system, I found that:

- Programmers tend to avoid creating a new subclass just to log a new message. 
  This results in lots of inappropriate reuse of the existing message classes, 
or hesitancy to log a message at all, reducing your ability to configure 
individual sets of messages you're interested in.  This is similar to the 
hesitancy to create a new exception subclass, but seems to be stronger - 
probably because you never 'catch' the logged messages, so the 
presence/absence of the class doesn't simplify/complicate other code.  In 
contrast, creating a new Logger (or "Category") instance meets little 
resistance, and a shift to that model was welcomed by all...except the 
developer of the message hierarchy logging system.

- Some messages are awfully hard to categorize statically:  the severity of a 
FileNotFound message could be FATAL, WARNING, or DEBUG, depending on what file 
is not found and the error-handling code around the message, so you end up 
needing multiple FileNotFound message classes. Thus, it is better for the 
calling code to determine the severity of a message, rather than some static 
property of the message itself.

- Configuring logging by message type is usually less helpful than enabling 
messages from a specific area of code, so configuring by package or class 
tends to be more useful.

I think the ideal would be to enable logging per thread, based on execution 
path:  'log all messages from any thread that has Class1.method2 in its 
stack', but I haven't worked with that yet.