Viewing file: LogUtil.py (6.65 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
######################################################################## # $Header: /var/local/cvsroot/4Suite/Ft/Server/Server/Lib/LogUtil.py,v 1.9 2005/03/14 07:38:20 mbrown Exp $ """ Functions and classes related to message logging
Copyright 2004 Fourthought, Inc. (USA). Detailed license and copyright information: http://4suite.org/COPYRIGHT Project home, documentation, distributions: http://4suite.org/ """
import sys, threading, time, os, socket
LOG_EMERG = ('emerg', 0) LOG_ALERT = ('alert', 1) LOG_CRIT = ('crit', 2) LOG_ERROR = LOG_ERR = ('error', 3) LOG_WARNING = LOG_WARN = ('warn', 4) LOG_NOTICE = ('notice', 5) LOG_INFO = ('info', 6) LOG_DEBUG = ('debug', 7)
_levels = {} for kword, value in locals().items(): if kword.startswith('LOG_'): _levels[value[0]] = value
_file_locks_lock = threading.Lock() _file_locks = {}
def FromString(level): if not level: raise ValueError('must not be empty')
value = _levels.get(level.lower()) if value is None: kwords = '|'.join(_levels.keys()) raise ValueError('must be one of ' + kwords)
return value
class ThreadSafeFile:
def __init__(self, name): name = os.path.abspath(name) _file_locks_lock.acquire() try: if not _file_locks.has_key(name): _file_locks[name] = threading.Lock() finally: _file_locks_lock.release() self.name = name self._lock = _file_locks[name] return
def __str__(self): return 'ThreadSafeFile(%s)' % self.name
def write(self, data): self._lock.acquire() try: fd = open(self.name, 'a') fd.write(data) fd.close() finally: self._lock.release() return
DEFAULT_LOGGER_BUFSIZE = 600 # lines
class Logger: def __init__(self, ident, logFile, maxLevel=LOG_INFO, showPid=0): self.buffer = [] self.buffer_maxsize = DEFAULT_LOGGER_BUFSIZE self.bufferIsFull = False self.ident = ident if isinstance(logFile, (file, ThreadSafeFile)): # An existing file-like object self.logFile = logFile.name self.stream = logFile else: # Assume it is a filename self.logFile = logFile self.stream = ThreadSafeFile(logFile) self.maxPriority, self.maxLevel = self.logLevel = maxLevel self.showPid = showPid return
def __str__(self): level = 'LOG_' + self.maxPriority.upper() return "<Logger %s, file %s, maxlevel %s>" % (self.ident, self.logFile, level)
def clone(self, ident, logLevel=None, showPid=None): # Create a new Logger instance with the given identifier if logLevel is None: logLevel = self.logLevel if showPid is None: showPid = self.showPid return self.__class__(ident, self.stream, logLevel, showPid)
def log(self, (priority, level), message): if level > self.maxLevel: # Ignore this message, more detail than we want to display return
# Create the message header: "mmm dd HH:MM:SS ident[pid]: <message>" strtime = time.strftime('%b %d %H:%M:%S', time.localtime(time.time())) if self.showPid: ident = '%s[%d]' % (self.ident, os.getpid()) else: ident = self.ident header = '%s %s: [%s]' % (strtime, ident, priority)
if message.endswith('\n'): # strip single trailing newline message = message[:-1]
# Map the header to each line of the message data = reduce(lambda data, line, header=header: data + '%s %s\n' % (header, line), message.split('\n'), '')
# attempt to write buffered messages if self.buffer: try: self.stream.write(''.join(self.buffer)) self.buffer = [] self.bufferIsFull = False except (IOError, socket.error): pass
# Write it out try: self.stream.write(data) except (IOError, socket.error): # if log temporarily unwritable, buffer the data if self.bufferIsFull: pass else: lines = data.split('\n') if len(self.buffer) + len(lines) > self.buffer_maxsize: self.bufferIsFull = True self.buffer.append('%s Additional messages exist but were not logged (buffer full)\n' % header) else: self.buffer += lines return
def emergency(self, msg): return self.log(LOG_EMERG, msg)
def alert(self, msg): return self.log(LOG_ALERT, msg)
def critical(self, msg): return self.log(LOG_CRIT, msg)
def error(self, msg): return self.log(LOG_ERR, msg)
def warning(self, msg): return self.log(LOG_WARNING, msg)
def notice(self, msg): return self.log(LOG_NOTICE, msg)
def info(self, msg): return self.log(LOG_INFO, msg)
def debug(self, msg): return self.log(LOG_DEBUG, msg)
class StreamLogger: """ A wrapper around a Logger instance which allows the log facility to be used in place of a stream object. """ def __init__(self, logger, priority): self._logger = logger self._priority = priority self._lock = threading.Lock() self._buffer = []
def flush(self): if self._buffer: self._lock.acquire() try: msg = ''.join(self._buffer) self._buffer = self._buffer[:0] finally: self._lock.release() self._logger.log(self._priority, msg) return
def write(self, str): if '\n' in str: parts = str.split('\n') self._lock.acquire() try: parts[0] = ''.join(self._buffer) + parts[0] self._buffer = parts[-1:] finally: self._lock.release() for msg in parts[:-1]: self._logger.log(self._priority, msg) else: self._buffer.append(str) return
def isatty(self): return False
class NullLogger: def emergency(self, msg): pass
def alert(self, msg): pass
def critical(self, msg): pass
def error(self, msg): pass
def warning(self, msg): pass
def notice(self, msg): pass
def info(self, msg): pass
def debug(self, msg): pass
|