1 # Copyright (c) 2003, The Regents of the University of California,
2 # through Lawrence Berkeley National Laboratory (subject to receipt of
3 # any required approvals from the U.S. Dept. of Energy). All rights
15 '''Logger interface, by default this class
16 will be used and logging calls are no-ops.
19 def __init__(self, msg):
21 def warning(self, *args, **kw):
23 def debug(self, *args, **kw):
25 def error(self, *args, **kw):
27 def setLevel(cls, level):
29 setLevel = classmethod(setLevel)
31 debugOn = lambda self: self.level >= DEBUG
32 warnOn = lambda self: self.level >= WARN
35 class BasicLogger(ILogger):
38 def __init__(self, msg, out=sys.stdout):
39 self.msg, self.out = msg, out
41 def warning(self, msg, *args, **kw):
42 if self.warnOn() is False: return
43 if BasicLogger.last != self.msg:
44 BasicLogger.last = self.msg
45 print >>self, "---- ", self.msg, " ----"
46 print >>self, " %s " %self.WARN,
47 print >>self, msg %args
49 def debug(self, msg, *args, **kw):
50 if self.debugOn() is False: return
51 if BasicLogger.last != self.msg:
52 BasicLogger.last = self.msg
53 print >>self, "---- ", self.msg, " ----"
54 print >>self, " %s " %self.DEBUG,
55 print >>self, msg %args
57 def error(self, msg, *args, **kw):
58 if BasicLogger.last != self.msg:
59 BasicLogger.last = self.msg
60 print >>self, "---- ", self.msg, " ----"
61 print >>self, " %s " %self.ERROR,
62 print >>self, msg %args
65 def write(self, *args):
66 '''Write convenience function; writes strings.
68 for s in args: self.out.write(s)
69 event = ''.join(*args)
72 _LoggerClass = BasicLogger
74 class GridLogger(ILogger):
75 def debug(self, msg, *args, **kw):
76 kw['component'] = self.msg
77 gridLog(event=msg %args, level='DEBUG', **kw)
79 def warning(self, msg, *args, **kw):
80 kw['component'] = self.msg
81 gridLog(event=msg %args, level='WARNING', **kw)
83 def error(self, msg, *args, **kw):
84 kw['component'] = self.msg
85 gridLog(event=msg %args, level='ERROR', **kw)
89 # Registry of send functions for gridLog
94 """Grid Logging Best Practices Record, Distributed Logging Utilities
96 The following names are reserved:
98 event -- log event name
99 Below is EBNF for the event name part of a log message.
100 name = <nodot> ( "." <name> )?
101 nodot = {RFC3896-chars except "."}
104 start: Immediately before the first action in a task.
105 end: Immediately after the last action in a task (that succeeded).
106 error: an error condition that does not correspond to an end event.
109 level -- logging level (see levels below)
110 status -- integer status code
111 gid -- global grid identifier
112 gid, cgid -- parent/child identifiers
116 More info: http://www.cedps.net/wiki/index.php/LoggingBestPractices#Python
118 reserved -- list of reserved names,
119 omitname -- list of reserved names, output only values ('ts', 'event',)
120 levels -- dict of levels and description
122 reserved = ('ts', 'event', 'level', 'status', 'gid', 'prog')
124 levels = dict(FATAL='Component cannot continue, or system is unusable.',
125 ALERT='Action must be taken immediately.',
126 CRITICAL='Critical conditions (on the system).',
127 ERROR='Errors in the component; not errors from elsewhere.',
128 WARNING='Problems that are recovered from, usually.',
129 NOTICE='Normal but significant condition.',
130 INFO='Informational messages that would be useful to a deployer or administrator.',
131 DEBUG='Lower level information concerning program logic decisions, internal state, etc.',
132 TRACE='Finest granularity, similar to "stepping through" the component or system.',
135 def __init__(self, date=None, **kw):
136 kw['ts'] = date or self.GLDate()
137 kw['gid'] = kw.get('gid') or os.getpid()
138 dict.__init__(self, kw)
143 from cStringIO import StringIO
144 s = StringIO(); n = " "
145 reserved = self.reserved; omitname = self.omitname; levels = self.levels
147 for k in ( list(filter(lambda i: self.has_key(i), reserved)) +
148 list(filter(lambda i: i not in reserved, self.keys()))
152 s.write( "%s " %self.format[type(v)](v) )
155 if k == reserved[2] and v not in levels:
158 s.write( "%s=%s " %(k, self.format[type(v)](v) ) )
164 """Grid logging Date Format
165 all timestamps should all be in the same time zone (UTC).
166 Grid timestamp value format that is a highly readable variant of the ISO8601 time standard [1]:
168 YYYY-MM-DDTHH:MM:SS.SSSSSSZ
171 def __new__(self, args=None):
172 """args -- datetime (year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])
175 args = args or datetime.datetime.utcnow()
176 l = (args.year, args.month, args.day, args.hour, args.minute, args.second,
177 args.microsecond, args.tzinfo or 'Z')
179 return str.__new__(self, "%04d-%02d-%02dT%02d:%02d:%02d.%06d%s" %l)
181 format = { int:str, float:lambda x: "%lf" % x, long:str, str:lambda x:x,
182 unicode:str, GLDate:str, }
186 """Send GLRecord, Distributed Logging Utilities
187 If the scheme is passed as a keyword parameter
188 the value is expected to be a callable function
189 that takes 2 parameters: url, outputStr
191 GRIDLOG_ON -- turn grid logging on
192 GRIDLOG_DEST -- provide URL destination
196 if not bool( int(os.environ.get('GRIDLOG_ON', 0)) ):
199 url = os.environ.get('GRIDLOG_DEST')
203 ## NOTE: urlparse problem w/customized schemes
205 scheme = url[:url.find('://')]
206 send = GLRegistry[scheme]
207 send( url, str(GLRecord(**kw)), )
208 except Exception, ex:
209 print >>sys.stderr, "*** gridLog failed -- %s" %(str(kw))
212 def sendUDP(url, outputStr):
213 from socket import socket, AF_INET, SOCK_DGRAM
214 idx1 = url.find('://') + 3; idx2 = url.find('/', idx1)
215 if idx2 < idx1: idx2 = len(url)
216 netloc = url[idx1:idx2]
217 host,port = (netloc.split(':')+[80])[0:2]
218 socket(AF_INET, SOCK_DGRAM).sendto( outputStr, (host,int(port)), )
220 def writeToFile(url, outputStr):
221 print >> open(url.split('://')[1], 'a+'), outputStr
223 GLRegistry["gridlog-udp"] = sendUDP
224 GLRegistry["file"] = writeToFile
227 def setBasicLogger():
230 setLoggerClass(BasicLogger)
231 BasicLogger.setLevel(0)
234 '''Use GridLogger for all logging events.
236 setLoggerClass(GridLogger)
238 def setBasicLoggerWARN():
241 setLoggerClass(BasicLogger)
242 BasicLogger.setLevel(WARN)
244 def setBasicLoggerDEBUG():
247 setLoggerClass(BasicLogger)
248 BasicLogger.setLevel(DEBUG)
250 def setLoggerClass(loggingClass):
251 '''Set Logging Class.
254 def setLoggerClass(loggingClass):
255 '''Set Logging Class.
257 assert issubclass(loggingClass, ILogger), 'loggingClass must subclass ILogger'
259 _LoggerClass = loggingClass
261 def setLevel(level=0):
262 '''Set Global Logging Level.
264 ILogger.level = level
270 '''Return instance of Logging class.
272 return _LoggerClass(msg)