# Perforce Defect Tracking Integration Project
#
#
# LOGGER.PY -- PROGRAM LOGGING CLASSES
#
# Gareth Rees, Ravenbrook Limited, 2000-10-16
#
#
# 1. INTRODUCTION
#
# This Python module implements classes for program logging -- recording
# information about the activity of a program.
#
# Logging is primarily intended to record what the integration does so that
# the administrator can:
#
# 1. undo it in an emergency [Requirements, 67];
#
# 2. debug their configuration [Requirements, 63];
#
# 3. remove the integration [Requirements, 64];
#
# and so that developers can:
#
# 4. debug modififcations of the system [Requirements, 25];
#
# 5. debug their extensions to new defect trackers [Requirements, 21].
#
# The intended readership of this document is project developers.
#
# This document is not confidential.
import message
import sys
import time
import types
# 2. ABSTRACT LOGGER CLASS
#
# "logger" is an abstract class for message logs, providing uniform message
# formatting and control of logging based on the priority of messages, but no
# actual logging.
#
# When constructing an instance of this class or a subclass, pass the minimum
# priority of message that should be written to the log (e.g., message.DEBUG to
# see all debug-level messages, or message.ERROR to only see errors).
class logger:
# Minimum priority of messages to log.
priority = message.INFO
def __init__(self, priority = message.INFO):
assert isinstance(priority, types.IntType)
self.priority = priority
# 2.1. Format a message with date
#
# format_with_date(msg). Format log message and return the message as a
# string. Messages are prefixed with the current date and time in UTC and
# the message id. See message.py for details of the formatting of message
# ids.
#
# The reason for the existence of this method is that not all logging
# methods record the date (in particular, file_logger doesn't).
def format_with_date(self, msg):
assert isinstance(msg, message.message)
date = time.strftime('%Y-%m-%d %H:%M:%S UTC', time.gmtime(time.time()))
return "%s %s" % (date, msg)
# 2.2 Log a message
#
# log(msg). Write the message to the log (using the write() method), but
# only if its priority is higher that self.priority.
def log(self, msg):
assert isinstance(msg, message.message)
# Higher priorities have lower numbers, hence the sense of this test.
if msg.priority <= self.priority:
self.write(msg)
# 2.4. Write a message to the log
#
# write(msg). Write the message to the log. There is no implementation in
# the logger class (it's an abstract class). Subclasses should provide the
# appopriate mechanism.
def write(self, msg):
assert isinstance(msg, message.message)
assert 0 # logger is an abstract class; no implementation of write().
# 3. FILE LOGGER CLASS
#
# This subclass of logger appends messages to a file stream, or to the standard
# output if no file is specified when the instance is created. The output
# buffer is flushed after each message is written so that the log can be
# recovered even if the program crashes.
class file_logger(logger):
file = None
def __init__(self, file = sys.stdout, priority = message.INFO):
assert isinstance(file, types.FileType)
logger.__init__(self, priority)
self.file = file
def write(self, msg):
assert isinstance(msg, message.message)
self.file.write(self.format_with_date(msg))
self.file.write('\n')
self.file.flush()
# 4. SYSTEM LOGGER CLASS
#
# This subclass of logger logs messages to the system log on Unix (using
# syslog). On other operating systems, it does nothing.
class sys_logger(logger):
def __init__(self, priority = message.INFO):
logger.__init__(self, priority)
import os
if os.name == 'posix':
import syslog
self.syslog = syslog.syslog
syslog.openlog('p4dti', syslog.LOG_PID, syslog.LOG_DAEMON)
syslog.setlogmask(syslog.LOG_UPTO(priority))
def syslog(self, priority, text):
pass
# 4.1. Log a message to the system log
#
# We override the log() method rather than the write() method because we
# use syslog's logmask feature instead of checking the priority ourselves.
def log(self, msg):
assert isinstance(msg, message.message)
self.syslog(msg.priority, str(msg))
# 4. MULTI_LOGGER CLASS
#
# This is a meta-logger that writes the message to each of a list of other
# loggers. This is so that the administrator can arrange for messages to go to
# several places in the integration configuration [AG, 5.1].
class multi_logger(logger):
loggers = []
def __init__(self, loggers = [], priority = message.INFO):
assert isinstance(loggers, types.ListType)
for l in loggers:
assert(isinstance(l, logger))
logger.__init__(self, priority)
self.loggers = loggers
def log(self, msg):
assert isinstance(msg, message.message)
for l in self.loggers:
l.log(msg)
# A. REFERENCES
#
# [AG] "Perforce Defect Tracking Integration Administrator's Guide" (living
# document); Richard Brooksby; Ravenbrook Limited; 2000-08-10.
#
# [Requirements] "Perforce Defect Tracking Integration Project Requirements"
# (living document); Gareth Rees; Ravenbrook Limited; 2000-05-24;
# .
#
#
# B. DOCUMENT HISTORY
#
# 2000-10-16 GDR Created.
#
# 2000-11-30 GDR Added some type checking.
#
# 2001-01-19 NB Added sys_logger.
#
# 2001-01-26 NB Removed extra \n.
#
# 2001-03-01 NB Fix for job000237.
#
# 2001-03-02 RB Transferred copyright to Perforce under their license.
#
# 2001-03-11 GDR Formatted as a document. Uses the message class. Check digit
# computation moved to message.py. Loggers pay attention to message priority.
#
# 2001-04-10 NB job000292: Added call to str() as our message objects
# were upsetting syslog.syslog.
#
# C. COPYRIGHT AND LICENCE
#
# This file is copyright (c) 2001 Perforce Software, Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
#
# $Id: //info.ravenbrook.com/project/p4dti/branch/2001-04-20/migrate-bugzilla/code/replicator/logger.py#1 $