|
|
@@ -1,298 +0,0 @@ |
|
|
|
# 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 |
|
|
|
import 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: i in self, 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) |