|
- # Copyright (c) 2003, The Regents of the University of California,
- # through Lawrence Berkeley National Laboratory (subject to receipt of
- # any required approvals from the U.S. Dept. of Energy). All rights
- # reserved.
- #
- """Logging"""
- ident = "$Id$"
- import os, sys
-
- WARN = 1
- DEBUG = 2
-
-
- class ILogger:
- '''Logger interface, by default this class
- will be used and logging calls are no-ops.
- '''
- level = 0
- def __init__(self, msg):
- return
- def warning(self, *args, **kw):
- return
- def debug(self, *args, **kw):
- return
- def error(self, *args, **kw):
- return
- def setLevel(cls, level):
- cls.level = level
- setLevel = classmethod(setLevel)
-
- debugOn = lambda self: self.level >= DEBUG
- warnOn = lambda self: self.level >= WARN
-
-
- class BasicLogger(ILogger):
- last = ''
-
- def __init__(self, msg, out=sys.stdout):
- self.msg, self.out = msg, out
-
- def warning(self, msg, *args, **kw):
- if self.warnOn() is False: return
- if BasicLogger.last != self.msg:
- BasicLogger.last = self.msg
- print >>self, "---- ", self.msg, " ----"
- print >>self, " %s " %self.WARN,
- print >>self, msg %args
- WARN = '[WARN]'
- def debug(self, msg, *args, **kw):
- if self.debugOn() is False: return
- if BasicLogger.last != self.msg:
- BasicLogger.last = self.msg
- print >>self, "---- ", self.msg, " ----"
- print >>self, " %s " %self.DEBUG,
- print >>self, msg %args
- DEBUG = '[DEBUG]'
- def error(self, msg, *args, **kw):
- if BasicLogger.last != self.msg:
- BasicLogger.last = self.msg
- print >>self, "---- ", self.msg, " ----"
- print >>self, " %s " %self.ERROR,
- print >>self, msg %args
- ERROR = '[ERROR]'
-
- def write(self, *args):
- '''Write convenience function; writes strings.
- '''
- for s in args: self.out.write(s)
- event = ''.join(*args)
-
-
- _LoggerClass = BasicLogger
-
- class GridLogger(ILogger):
- def debug(self, msg, *args, **kw):
- kw['component'] = self.msg
- gridLog(event=msg %args, level='DEBUG', **kw)
-
- def warning(self, msg, *args, **kw):
- kw['component'] = self.msg
- gridLog(event=msg %args, level='WARNING', **kw)
-
- def error(self, msg, *args, **kw):
- kw['component'] = self.msg
- gridLog(event=msg %args, level='ERROR', **kw)
-
-
- #
- # Registry of send functions for gridLog
- #
- GLRegistry = {}
-
- class GLRecord(dict):
- """Grid Logging Best Practices Record, Distributed Logging Utilities
-
- The following names are reserved:
-
- event -- log event name
- Below is EBNF for the event name part of a log message.
- name = <nodot> ( "." <name> )?
- nodot = {RFC3896-chars except "."}
-
- Suffixes:
- start: Immediately before the first action in a task.
- end: Immediately after the last action in a task (that succeeded).
- error: an error condition that does not correspond to an end event.
-
- ts -- timestamp
- level -- logging level (see levels below)
- status -- integer status code
- gid -- global grid identifier
- gid, cgid -- parent/child identifiers
- prog -- program name
-
-
- More info: http://www.cedps.net/wiki/index.php/LoggingBestPractices#Python
-
- reserved -- list of reserved names,
- omitname -- list of reserved names, output only values ('ts', 'event',)
- levels -- dict of levels and description
- """
- reserved = ('ts', 'event', 'level', 'status', 'gid', 'prog')
- omitname = ()
- levels = dict(FATAL='Component cannot continue, or system is unusable.',
- ALERT='Action must be taken immediately.',
- CRITICAL='Critical conditions (on the system).',
- ERROR='Errors in the component; not errors from elsewhere.',
- WARNING='Problems that are recovered from, usually.',
- NOTICE='Normal but significant condition.',
- INFO='Informational messages that would be useful to a deployer or administrator.',
- DEBUG='Lower level information concerning program logic decisions, internal state, etc.',
- TRACE='Finest granularity, similar to "stepping through" the component or system.',
- )
-
- def __init__(self, date=None, **kw):
- kw['ts'] = date or self.GLDate()
- kw['gid'] = kw.get('gid') or os.getpid()
- dict.__init__(self, kw)
-
- def __str__(self):
- """
- """
- from cStringIO import StringIO
- s = StringIO(); n = " "
- reserved = self.reserved; omitname = self.omitname; levels = self.levels
-
- for k in ( list(filter(lambda i: self.has_key(i), reserved)) +
- list(filter(lambda i: i not in reserved, self.keys()))
- ):
- v = self[k]
- if k in omitname:
- s.write( "%s " %self.format[type(v)](v) )
- continue
-
- if k == reserved[2] and v not in levels:
- pass
-
- s.write( "%s=%s " %(k, self.format[type(v)](v) ) )
-
- s.write("\n")
- return s.getvalue()
-
- class GLDate(str):
- """Grid logging Date Format
- all timestamps should all be in the same time zone (UTC).
- Grid timestamp value format that is a highly readable variant of the ISO8601 time standard [1]:
-
- YYYY-MM-DDTHH:MM:SS.SSSSSSZ
-
- """
- def __new__(self, args=None):
- """args -- datetime (year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])
- """
- import datetime
- args = args or datetime.datetime.utcnow()
- l = (args.year, args.month, args.day, args.hour, args.minute, args.second,
- args.microsecond, args.tzinfo or 'Z')
-
- return str.__new__(self, "%04d-%02d-%02dT%02d:%02d:%02d.%06d%s" %l)
-
- format = { int:str, float:lambda x: "%lf" % x, long:str, str:lambda x:x,
- unicode:str, GLDate:str, }
-
-
- def gridLog(**kw):
- """Send GLRecord, Distributed Logging Utilities
- If the scheme is passed as a keyword parameter
- the value is expected to be a callable function
- that takes 2 parameters: url, outputStr
-
- GRIDLOG_ON -- turn grid logging on
- GRIDLOG_DEST -- provide URL destination
- """
- import os
-
- if not bool( int(os.environ.get('GRIDLOG_ON', 0)) ):
- return
-
- url = os.environ.get('GRIDLOG_DEST')
- if url is None:
- return
-
- ## NOTE: urlparse problem w/customized schemes
- try:
- scheme = url[:url.find('://')]
- send = GLRegistry[scheme]
- send( url, str(GLRecord(**kw)), )
- except Exception, ex:
- print >>sys.stderr, "*** gridLog failed -- %s" %(str(kw))
-
-
- def sendUDP(url, outputStr):
- from socket import socket, AF_INET, SOCK_DGRAM
- idx1 = url.find('://') + 3; idx2 = url.find('/', idx1)
- if idx2 < idx1: idx2 = len(url)
- netloc = url[idx1:idx2]
- host,port = (netloc.split(':')+[80])[0:2]
- socket(AF_INET, SOCK_DGRAM).sendto( outputStr, (host,int(port)), )
-
- def writeToFile(url, outputStr):
- print >> open(url.split('://')[1], 'a+'), outputStr
-
- GLRegistry["gridlog-udp"] = sendUDP
- GLRegistry["file"] = writeToFile
-
-
- def setBasicLogger():
- '''Use Basic Logger.
- '''
- setLoggerClass(BasicLogger)
- BasicLogger.setLevel(0)
-
- def setGridLogger():
- '''Use GridLogger for all logging events.
- '''
- setLoggerClass(GridLogger)
-
- def setBasicLoggerWARN():
- '''Use Basic Logger.
- '''
- setLoggerClass(BasicLogger)
- BasicLogger.setLevel(WARN)
-
- def setBasicLoggerDEBUG():
- '''Use Basic Logger.
- '''
- setLoggerClass(BasicLogger)
- BasicLogger.setLevel(DEBUG)
-
- def setLoggerClass(loggingClass):
- '''Set Logging Class.
- '''
-
- def setLoggerClass(loggingClass):
- '''Set Logging Class.
- '''
- assert issubclass(loggingClass, ILogger), 'loggingClass must subclass ILogger'
- global _LoggerClass
- _LoggerClass = loggingClass
-
- def setLevel(level=0):
- '''Set Global Logging Level.
- '''
- ILogger.level = level
-
- def getLevel():
- return ILogger.level
-
- def getLogger(msg):
- '''Return instance of Logging class.
- '''
- return _LoggerClass(msg)
-
|