home *** CD-ROM | disk | FTP | other *** search
- import blue
- import sys
- import traceback
- #import string
- #import stackless
- from logConstants import *
- import __builtin__
-
- channels = {}
-
- INFO = 1
- WARN = 2
- ERR = 4
- FATAL = 8
- OVERLAP = 16
- PERF = 32
-
- _w = 79
-
- traceID = 1L
-
- def LogException(channel="general", extraText="", toConsole=1, toLogServer=1, toMsgWindow=1, exctype=None, exc=None, tb=None, severity=None):
- _tmpctx = blue.pyos.SwitchTaskletTimer("Logging::LogException")
- try:
- try:
- if exctype is None and exc is None:
- exctype, exc, tb = sys.exc_info()
- try:
- if severity is None:
- severity = (ERR, WARN)[isinstance(exc, UserError)]
- if toMsgWindow and isinstance(exc, UserError) and boot.role == "client":
- toMsgWindow = 0
- eve.Message(*exc.args)
- out = GetMultiplex(channel, severity, [toConsole,0][toLogServer==1], toLogServer, toMsgWindow)
- pre = ('', 'REMOTE')[channel == "remote.exc"]
- global traceID
- tmpTraceID = traceID
- traceID += 1
- print >> out, ("\n\n\n%sEXCEPTION #%d logged at " % (pre,tmpTraceID,)), blue.os.FormatUTC()[0], blue.os.FormatUTC()[2], extraText
- traceback.print_exception(exctype, exc, tb, file=out)
- _LogContext(tb, out)
- finally:
- # IMPORTANT: If you don't nullify the output of sys.exc_info(), you leak a lot.
- exctype = None
- exc = None
- tb = None
- _LogSession(out)
- print >> out, "\n\n\n"
- out.flush()
- if toConsole:
- if toLogServer:
- print >> sys.stderr, "An exception has occurred. It has been logged in the log server as exception #%d"%tmpTraceID
- else:
- print >> sys.stderr, "There is no useful information accompanying this exception in the log server"
- except:
- try:
- traceback.print_exc()
- except:
- try:
- print >> sys.stderr, "A major @^#$%! occurred in the LogException function."
- except:
- print >> sys.stderr, "<dang. it did it again..."
- finally:
- blue.pyos.SwitchTaskletTimer(_tmpctx)
-
- # logging tracebacks for debugging
- def LogTraceback(channel="nonsvc.trace", extraText="", toConsole=1, toLogServer=1, nthParent=0, daStack=None, severity=ERR):
- _tmpctx = blue.pyos.SwitchTaskletTimer("Logging::LogTraceback")
- try:
- if daStack is None:
- daStack = traceback.extract_stack()
- out = GetMultiplex(channel, severity, [toConsole,0][toLogServer==1], toLogServer, 0) # no debug tracebacks logged out to msg windows...
- global traceID
- tmpTraceID = traceID
- traceID += 1
- print >> out, '_' * _w
- print >> out, "\nSTACKTRACE #%d logged at"%tmpTraceID, blue.os.FormatUTC()[0], blue.os.FormatUTC()[2]
- if extraText: print >> out, extraText
- traceback.print_list(daStack[:-(nthParent+1)], out)
- _LogSession(out)
- print >> out, "\nspam END%s" % ('_' * (_w-len("spam END")))
- out.flush()
- if toConsole:
- if toLogServer:
- print >> sys.stderr, "A traceback has been generated. It has been logged in the log server as stacktrace #%d"%tmpTraceID
- else:
- print >> sys.stderr, "There is no useful information accompanying this traceback in the log server"
- finally:
- blue.pyos.SwitchTaskletTimer(_tmpctx)
-
- # legacy bitches
-
- def StackTrace(channel = "general", toConsole = 0, text = ""):
- toConsole, toLogServer, toMsgWindow = [
- (0, 1, 0), # 0 for logger only
- (1, 1, 1), # 1 for both logger and console
- (1, 0, 1), # 2 for console only
- (1, 1, 0), # 3 for both logger and console - but not the god awful pop up window.
- ][toConsole]
- exctype, exc, tb = sys.exc_info()
- try:
- if exc: return LogException(channel, text, toConsole, toLogServer, toMsgWindow, exctype, exc, tb)
- else: return LogTraceback(channel, text, toConsole, toLogServer, 1)
- finally:
- # IMPORTANT: If you don't nullify the output of sys.exc_info(), you leak a lot.
- exctype = None
- exc = None
- tb = None
- __builtin__.StackTrace = StackTrace
-
- #___________________________________________________________________________
-
- # stop reading; internals follow
-
- def _LogSession(out):
- eve = getattr(__builtin__, "eve", None)
- if eve: print >> out, "\neve.session was", eve.session
- elif hasattr(__builtin__, "session"): print >> out, "session was", session
- else: print >> out, "sorry, no session for ya."
- ctk = GetLocalStorage().get('calltimer.key',None)
- if ctk: print >> out, "calltimer.key was", ctk
- currentcall = GetLocalStorage().get('base.currentcall',None)
- if currentcall:
- try:
- currentcall = currentcall()
- print >> out, "currentcall was: "+str(currentcall)
- except ReferenceError:
- pass
-
- def _LogContext(tb, out):
- try:
- if tb is None:
- print >> out, "No context info available."
- return
- while tb.tb_next is not None:
- tb = tb.tb_next
-
- argnames = tb.tb_frame.f_code.co_varnames[:tb.tb_frame.f_code.co_argcount+1]
- varnames = tb.tb_frame.f_code.co_varnames[tb.tb_frame.f_code.co_argcount+1:]
- locals_ = tb.tb_frame.f_locals.copy()
- if argnames:
- print >> out, "\n\nThis function was called with arguments:\n"
- for each in argnames:
- try:
- theStr = repr(locals_[each])
- except:
- theStr = "<not found>"
- print >> out, each, ':\t\t', theStr
- else: print >> out, "\n\nThe function was called with no arguments, or this was a non-python context."
-
- if varnames:
- print >> out, "\n\nBarring function arguments, the local namespace looked like this:\n"
- for each in varnames:
- try:
- theStr = repr(locals_[each])
- print >> out, each, ':\t\t', theStr
- except:
- pass
-
- elif argnames: print >> out, "\n\nBarring function arguments, the local namespace was empty.\n"
- else: print >> out, "\n\nThe local namespace was empty, or this was a non-python context."
-
- finally:
- out = frame = tb = argnames = varnames = locals_ = None
-
- # stream thunkas
-
- def GetMultiplex(channel, mode, toConsole, toLogServer, toMsgWindow):
- to = []
- if toConsole:
- if mode == INFO:
- to.append(sys.stdout)
- else:
- to.append(sys.stderr)
- if toLogServer:
- if channel not in channels:
- if '.' in channel:
- prefix = channel.split('.')[0]
- name = '.'.join(channel.split('.')[1:])
- channels[channel] = blue.pyos.CreateLogChannel(prefix, name)
- else:
- channels[channel] = blue.pyos.CreateLogChannel(boot.codename, channel)
- to.append(LogChannelStream(channels[channel], mode))
- if toMsgWindow and hasattr(__builtin__, "eve"): to.append(MsgWindowStream())
- return Multiplex(to)
-
- class LogChannelStream:
- def __init__(self, channel, mode): self.channel, self.mode, self.buff = channel, mode, ''
- def write(self, what): self.buff = ''.join((self.buff, what))
- def flush(self):
- linecount = 0
- for each in self.buff.replace('%', '%%').split('\n'):
- if each.strip():
- try:
- each = each
- for i in range(0,10120,253): # forty lines max. - IT ISN'T COVERING ALL CASES!!
- if i==0:
- if len(each)<=255:
- x = each
- else:
- x = each[:(i+253)]
- else:
- x = " - " + each[i:(i+253)]
- self.channel.Log(x, self.mode)
- if (i+253)>=len(each):
- break
- linecount += 1
- if linecount > 200:
- self.channel.Log("==========> Well that's it. I usually give up after spewing out 200 lines. The buffer was %s KB" % (len(self.buff)/1024), ERR)
- return
- except TypeError:
- self.channel.Log("Some bastard exception nuked us with crappy info... Let's give'm 'll", ERR)
- each = each.replace('\0','\\0')
- self.channel.Log(each, self.mode)
- if self.mode == FATAL: self.mode = ERR # hack? or is it ok that only the first line is fatal even if e really meant to log to fatal?
-
- class MsgWindowStream:
- def __init__(self): self.buff = ''
- def write(self, what): self.buff = ''.join((self.buff, what))
- def flush(self):
- for bad, good in [("<", "<"), (">", ">"), ("\r", ""), ("\n", "<br>")]:
- self.buff = self.buff.replace(bad, good)
- Import("uthread")
- if len(self.buff) > 10000:
- self.buff = self.buff[:10000] + "... [long traceback clipped; more info in the logger]"
- uthread.new(eve.Message, "ErrSystemError", {"text": self.buff})
-
-
- class Multiplex:
- def __init__(self, streams): self.streams = streams
- def write(self, what):
- for each in self.streams: each.write(what)
- def flush(self):
- for each in self.streams: getattr(each, "flush", lambda:None)() # oky, our sys.stdout doesn't have a flush ...
-
-