In a lot of different applications written by the author, the same requirements crop up over and over again relative to error message handling:
All error messages are always written to the standard error stream.
A standardized prefix is attached to all error message lines, so they will stand out if mingled with other streams.
If desired, all messages will also be written to one or more log files.
The user can query to find out how many error messages have been issued up to the current time.
The messages may be of multiple classes (error, warning, informational, and so on) and counts of each error class are maintained separately.
The Log class presented here centralizes these services.
This class is an obvious application of the Singleton
design pattern; see Section 45, “The singleton class: A classic design pattern”. In
practice, this means that the Log()
constructor can be called any number of times from any
number of locations in a program, but they will all use the
same, single instance.
Here is the interface to the Log class.
Log()
Returns the singleton instance of Log.
Initially, it will transmit messages only to the
standard error stream.
.addLogFile(fileName)
Use this method to instruct the instance to send errors to
a file whose name is . If that file cannot be
opened new for writing, it will raise an fileNameIOError exception.
If the file name is passed to the instance more than once, successive calls will be ignored.
.setPrefix(s)
Sets the string that is prefixed to all messages to
. The
default value is s'*** '.
.msgKind ( kind, *L )
This method sends a message of a specific category.
There are two predefined categories, whose values (as
strings) are given by the constants ERROR_KIND (currently "Error") and WARNING_KIND (currently "Warning"). You may define additional
categories by passing the category name as the msgKind argument.
The remaining arguments must also be strings, which are all concatenated together and written to all the current message destinations, with each line preceded by the current prefix, and the contents of the first line also preceded by the category name and a colon.
Here's an example of the call. Assume that nGoofs is 3 and the standard error prefix
is still in force.
Log().msgKind('Notice', 'There have been ', str(nGoofs),
' goofs so far.\nThese goofs were not fatal.' )
Here's the output that call will send to the current set of destinations:
*** Notice: There have been 3 goofs so far. *** These goofs were not fatal.
.error(*L)
Sends an error message. Same as .msgKind(ERROR_KIND, *L).
.warning(*L)
Sends a warning message. Same as .msgKind(WARNING_KIND, *L).
.message ( *L )
Sends a message to the current destinations. The arguments are one or more strings, which are concatenated to form the message. The current prefix will be prepended to each line of the message.
.write ( *L )
Like .message(), but does not prepend
the current prefix.
.fatal ( *L )
To write a final message and then terminate execution of the program, call this method, and pass it one or more strings, which will be concatenated to form the message.
.count ( kind=None )
Returns the number of messages of the given kind since the first instantation of this
class. If no kind argument is passed,
ERROR_KIND is the default.