home *** CD-ROM | disk | FTP | other *** search
/ Enter 2004 April / enter-2004-04.iso / files / EVE_1424_100181.exe / log.py < prev    next >
Encoding:
Python Source  |  2004-04-20  |  9.8 KB  |  236 lines

  1. import blue
  2. import sys
  3. import traceback
  4. #import string
  5. #import stackless
  6. from logConstants import *
  7. import __builtin__
  8.  
  9. channels = {}
  10.  
  11. INFO = 1
  12. WARN = 2
  13. ERR = 4
  14. FATAL = 8
  15. OVERLAP = 16
  16. PERF = 32
  17.  
  18. _w = 79
  19.  
  20. traceID = 1L
  21.  
  22. def LogException(channel="general", extraText="", toConsole=1, toLogServer=1, toMsgWindow=1, exctype=None, exc=None, tb=None, severity=None):
  23.     _tmpctx = blue.pyos.SwitchTaskletTimer("Logging::LogException")
  24.     try:
  25.         try:
  26.             if exctype is None and exc is None:
  27.                 exctype, exc, tb = sys.exc_info()
  28.             try:
  29.                 if severity is None:
  30.                     severity = (ERR, WARN)[isinstance(exc, UserError)]
  31.                 if toMsgWindow and isinstance(exc, UserError) and boot.role == "client":
  32.                     toMsgWindow = 0
  33.                     eve.Message(*exc.args)
  34.                 out = GetMultiplex(channel, severity, [toConsole,0][toLogServer==1], toLogServer, toMsgWindow)
  35.                 pre = ('', 'REMOTE')[channel == "remote.exc"]
  36.                 global traceID
  37.                 tmpTraceID = traceID
  38.                 traceID += 1
  39.                 print >> out, ("\n\n\n%sEXCEPTION #%d logged at " % (pre,tmpTraceID,)), blue.os.FormatUTC()[0], blue.os.FormatUTC()[2], extraText
  40.                 traceback.print_exception(exctype, exc, tb, file=out)
  41.                 _LogContext(tb, out)
  42.             finally:
  43.                 # IMPORTANT:  If you don't nullify the output of sys.exc_info(), you leak a lot.
  44.                 exctype = None
  45.                 exc     = None
  46.                 tb      = None
  47.             _LogSession(out)
  48.             print >> out, "\n\n\n"
  49.             out.flush()
  50.             if toConsole:
  51.                 if toLogServer:
  52.                     print >> sys.stderr, "An exception has occurred.  It has been logged in the log server as exception #%d"%tmpTraceID
  53.                 else:
  54.                     print >> sys.stderr, "There is no useful information accompanying this exception in the log server"
  55.         except:
  56.             try:
  57.                 traceback.print_exc()
  58.             except:
  59.                 try:
  60.                     print >> sys.stderr, "A major @^#$%! occurred in the LogException function."
  61.                 except:
  62.                     print >> sys.stderr, "<dang.  it did it again..."
  63.     finally:
  64.         blue.pyos.SwitchTaskletTimer(_tmpctx)
  65.  
  66. # logging tracebacks for debugging
  67. def LogTraceback(channel="nonsvc.trace", extraText="", toConsole=1, toLogServer=1, nthParent=0, daStack=None, severity=ERR):
  68.     _tmpctx = blue.pyos.SwitchTaskletTimer("Logging::LogTraceback")
  69.     try:
  70.         if daStack is None:
  71.             daStack = traceback.extract_stack()
  72.         out = GetMultiplex(channel, severity, [toConsole,0][toLogServer==1], toLogServer, 0) # no debug tracebacks logged out to msg windows...
  73.         global traceID
  74.         tmpTraceID = traceID
  75.         traceID += 1
  76.         print >> out, '_' * _w
  77.         print >> out, "\nSTACKTRACE #%d logged at"%tmpTraceID,  blue.os.FormatUTC()[0], blue.os.FormatUTC()[2]
  78.         if extraText: print >> out, extraText
  79.         traceback.print_list(daStack[:-(nthParent+1)], out)
  80.         _LogSession(out)
  81.         print >> out, "\nspam END%s" % ('_' * (_w-len("spam END")))
  82.         out.flush()
  83.         if toConsole:
  84.             if toLogServer:
  85.                 print >> sys.stderr, "A traceback has been generated.  It has been logged in the log server as stacktrace #%d"%tmpTraceID
  86.             else:
  87.                 print >> sys.stderr, "There is no useful information accompanying this traceback in the log server"
  88.     finally:
  89.         blue.pyos.SwitchTaskletTimer(_tmpctx)
  90.  
  91. # legacy bitches
  92.  
  93. def StackTrace(channel = "general", toConsole = 0, text = ""):
  94.     toConsole, toLogServer, toMsgWindow = [
  95.             (0, 1, 0), # 0 for logger only
  96.             (1, 1, 1), # 1 for both logger and console
  97.             (1, 0, 1), # 2 for console only
  98.             (1, 1, 0), # 3 for both logger and console - but not the god awful pop up window.
  99.             ][toConsole]
  100.     exctype, exc, tb = sys.exc_info()
  101.     try:
  102.         if exc: return LogException(channel, text, toConsole, toLogServer, toMsgWindow, exctype, exc, tb)
  103.         else: return LogTraceback(channel, text, toConsole, toLogServer, 1)
  104.     finally:
  105.         # IMPORTANT:  If you don't nullify the output of sys.exc_info(), you leak a lot.
  106.         exctype = None
  107.         exc     = None
  108.         tb      = None
  109. __builtin__.StackTrace = StackTrace
  110.  
  111. #___________________________________________________________________________
  112.  
  113. # stop reading; internals follow
  114.  
  115. def _LogSession(out):
  116.     eve = getattr(__builtin__, "eve", None)
  117.     if eve: print >> out, "\neve.session was", eve.session
  118.     elif hasattr(__builtin__, "session"): print >> out, "session was", session
  119.     else: print >> out, "sorry, no session for ya."
  120.     ctk = GetLocalStorage().get('calltimer.key',None)
  121.     if ctk: print >> out, "calltimer.key was", ctk
  122.     currentcall = GetLocalStorage().get('base.currentcall',None)
  123.     if currentcall:
  124.         try:
  125.             currentcall = currentcall()
  126.             print >> out, "currentcall was: "+str(currentcall)
  127.         except ReferenceError:
  128.             pass
  129.  
  130. def _LogContext(tb, out):
  131.     try:
  132.         if tb is None:
  133.             print >> out, "No context info available."
  134.             return
  135.         while tb.tb_next is not None:
  136.             tb = tb.tb_next
  137.  
  138.         argnames = tb.tb_frame.f_code.co_varnames[:tb.tb_frame.f_code.co_argcount+1]
  139.         varnames = tb.tb_frame.f_code.co_varnames[tb.tb_frame.f_code.co_argcount+1:]
  140.         locals_ = tb.tb_frame.f_locals.copy()
  141.         if argnames:
  142.             print >> out, "\n\nThis function was called with arguments:\n"
  143.             for each in argnames:
  144.                 try:
  145.                     theStr = repr(locals_[each])
  146.                 except:
  147.                     theStr = "<not found>"
  148.                 print >> out, each, ':\t\t', theStr
  149.         else: print >> out, "\n\nThe function was called with no arguments, or this was a non-python context."
  150.  
  151.         if varnames:
  152.             print >> out, "\n\nBarring function arguments, the local namespace looked like this:\n"
  153.             for each in varnames:
  154.                 try:
  155.                     theStr = repr(locals_[each])
  156.                     print >> out, each, ':\t\t', theStr
  157.                 except:
  158.                     pass
  159.  
  160.         elif argnames: print >> out, "\n\nBarring function arguments, the local namespace was empty.\n"
  161.         else: print >> out, "\n\nThe local namespace was empty, or this was a non-python context."
  162.  
  163.     finally:
  164.         out = frame = tb = argnames = varnames = locals_ = None
  165.  
  166. # stream thunkas
  167.  
  168. def GetMultiplex(channel, mode, toConsole, toLogServer, toMsgWindow):
  169.     to = []
  170.     if toConsole:
  171.         if mode == INFO:
  172.             to.append(sys.stdout)
  173.         else:
  174.             to.append(sys.stderr)
  175.     if toLogServer:
  176.         if channel not in channels:
  177.             if '.' in channel:
  178.                 prefix = channel.split('.')[0]
  179.                 name = '.'.join(channel.split('.')[1:])
  180.                 channels[channel] = blue.pyos.CreateLogChannel(prefix, name)
  181.             else:
  182.                 channels[channel] = blue.pyos.CreateLogChannel(boot.codename, channel)
  183.         to.append(LogChannelStream(channels[channel], mode))
  184.     if toMsgWindow and hasattr(__builtin__, "eve"): to.append(MsgWindowStream())
  185.     return Multiplex(to)
  186.  
  187. class LogChannelStream:
  188.     def __init__(self, channel, mode): self.channel, self.mode, self.buff = channel, mode, ''
  189.     def write(self, what): self.buff = ''.join((self.buff, what))
  190.     def flush(self):
  191.         linecount = 0
  192.         for each in self.buff.replace('%', '%%').split('\n'):
  193.             if each.strip():
  194.                 try:
  195.                     each = each
  196.                     for i in range(0,10120,253): # forty lines max. - IT ISN'T COVERING ALL CASES!!
  197.                         if i==0:
  198.                             if len(each)<=255:
  199.                                 x = each
  200.                             else:
  201.                                 x = each[:(i+253)]
  202.                         else:
  203.                             x = " - " + each[i:(i+253)]
  204.                         self.channel.Log(x, self.mode)
  205.                         if (i+253)>=len(each):
  206.                             break
  207.                         linecount += 1
  208.                         if linecount > 200:
  209.                             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)
  210.                             return
  211.                 except TypeError:
  212.                     self.channel.Log("Some bastard exception nuked us with crappy info...  Let's give'm 'll", ERR)
  213.                     each = each.replace('\0','\\0')
  214.                     self.channel.Log(each, self.mode)
  215.                 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?
  216.  
  217. class MsgWindowStream:
  218.     def __init__(self): self.buff = ''
  219.     def write(self, what): self.buff = ''.join((self.buff, what))
  220.     def flush(self):
  221.         for bad, good in [("<", "<"), (">", ">"), ("\r", ""), ("\n", "<br>")]:
  222.             self.buff = self.buff.replace(bad, good)
  223.         Import("uthread")
  224.         if len(self.buff) > 10000:
  225.             self.buff = self.buff[:10000] + "... [long traceback clipped; more info in the logger]"
  226.         uthread.new(eve.Message, "ErrSystemError", {"text": self.buff})
  227.  
  228.  
  229. class Multiplex:
  230.     def __init__(self, streams): self.streams = streams
  231.     def write(self, what):
  232.         for each in self.streams: each.write(what)
  233.     def flush(self):
  234.         for each in self.streams: getattr(each, "flush", lambda:None)() # oky, our sys.stdout doesn't have a flush ...
  235.  
  236.