Next / Previous / Contents / Shipman's homepage

10. class Log

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 specification function named log-outputs to describe the current set of places where messages will be sent.

logscan.py
# - - - - -   S p e c i f i c a t i o n   f u n c t i o n s

# 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.

logscan.py
      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.

logscan.py
    __prefix = DEFAULT_PREFIX
    __logMap = {'': sys.stderr}
    __kindCounts = {}