The intended functions below are the formal descriptions of the
interface. They should match the informal descriptions given in
Section 3, “The singleton Log object”. First we define a verification function
named log-outputs to describe the current set
of places where messages will be sent.
#================================================================
# Verification functions
#----------------------------------------------------------------
# log-outputs(Log) ==
# (sys.stderr) + (all log files of Log)
#----------------------------------------------------------------
# - - - - - c l a s s L o g
class Log(Singleton):
'''Error logging object.
Exports:
Log():
[ if Log has been instantiated before ->
return that instance
else ->
return a new instance logging only to sys.stderr,
with prefix DEFAULT_PREFIX and no error counts ]
.addLogFile ( fileName ):
[ fileName is a string ->
if fileName has been passed to this method before ->
I
else if fileName can be opened new for writing ->
self := self with that file so opened and added
to log-outputs(self) ]
else -> raise IOError ]
.setPrefix ( s ):
[ s is a string ->
self := self with the current prefix changed to s ]
.msgKind ( kind, *L ):
[ if (kind) is a key in self.__kindCounts ->
self.__kindCounts[kind] +:= 1
else ->
self.__kindCounts[kind] := 1
In any case ->
log-outputs(self) := lines made from the
concatenation of *L, broken on newlines, with each
line preceded by the current prefix, and the text
of the first line preceded by (kind) ]
.error ( *L ):
[ equivalent to self.msgKing ( ERROR_KIND, *L ) ]
.warning ( *L ):
[ equivalent to self.msgKing ( WARNING_KIND, *L ) ]
.message ( *L ):
[ L is a list of strings ->
log-outputs(self) := lines made from the concatenation
of L, broken on newlines, with each line preceded
by the current prefix ]
.write ( *L ):
[ L is a list of strings ->
log-outputs(self) := the concatenation of L ]
.fatal ( *L ):
[ L is a list of strings ->
log-outputs(self) := lines made from the concatenation
of L, broken on newlines, with each line preceded
by the current prefix
stop execution ]
.count ( kind ):
[ kind is a string ->
if kind is a key in self.__kindCounts ->
return self.__kindCounts[kind]
else -> return 0 ]
Here are the internal state attributes of the class.
State/Invariants:
.__prefix:
[ the current prefix string ]
.__logMap:
[ a dictionary whose keys are the names of log files
requested by .addLogFile, and each related value is
that file, opened for writing ]
.__kindCounts:
[ a dictionary whose keys are the unique (kind) arguments
passed to .msgKind(), and each related value is the
count of messages of that kind ]
'''
Because this is a singleton, the constructor may be called many times on the same instance. Therefore, we'll just establish the class invariants as class variables. This means we don't need to define a constructor.
__prefix = DEFAULT_PREFIX
__logMap = {'': sys.stderr}
__kindCounts = {}