working exception variable dump

This commit is contained in:
Darren Ranalli 2008-09-03 21:16:09 +00:00
parent 9c9d3d0707
commit e79a864125
4 changed files with 111 additions and 20 deletions

View File

@ -1,8 +1,11 @@
from pandac.PandaModules import ConfigConfigureGetConfigConfigShowbase as config
from direct.directnotify.DirectNotifyGlobal import directNotify from direct.directnotify.DirectNotifyGlobal import directNotify
from direct.showbase.PythonUtil import fastRepr from direct.showbase.PythonUtil import fastRepr
from exceptions import Exception from exceptions import Exception
import sys import sys
import traceback import types
notify = directNotify.newCategory("ExceptionVarDump")
reentry = 0 reentry = 0
@ -11,30 +14,33 @@ def _varDump__init__(self, *args, **kArgs):
if reentry > 0: if reentry > 0:
return return
reentry += 1 reentry += 1
# frame zero is this frame
f = 1 f = 1
self._savedExcString = None self._savedExcString = None
self._savedStackFrames = [] self._savedStackFrames = []
while True: while True:
try: try:
frame = sys._getframe(f) frame = sys._getframe(f)
except ValueError, e:
break
else:
f += 1 f += 1
self._savedStackFrames.append(frame) self._savedStackFrames.append(frame)
except:
break
self._moved__init__(*args, **kArgs) self._moved__init__(*args, **kArgs)
reentry -= 1 reentry -= 1
sReentry = 0 sReentry = 0
def _varDump__str__(self, *args, **kArgs): def _varDump__print(exc):
global sReentry global sReentry
global notify
if sReentry > 0: if sReentry > 0:
return return
sReentry += 1 sReentry += 1
if not self._savedExcString: if not exc._savedExcString:
s = '' s = ''
foundRun = False foundRun = False
for frame in reversed(self._savedStackFrames): for frame in reversed(exc._savedStackFrames):
filename = frame.f_code.co_filename filename = frame.f_code.co_filename
codename = frame.f_code.co_name codename = frame.f_code.co_name
if not foundRun and codename != 'run': if not foundRun and codename != 'run':
@ -48,17 +54,59 @@ def _varDump__str__(self, *args, **kArgs):
obj = locals[var] obj = locals[var]
rep = fastRepr(obj) rep = fastRepr(obj)
s += '::%s = %s\n' % (var, rep) s += '::%s = %s\n' % (var, rep)
self._savedExcString = s exc._savedExcString = s
self._savedStackFrames = None exc._savedStackFrames = None
notify = directNotify.newCategory("ExceptionVarDump") notify.info(exc._savedExcString)
notify.info(self._savedExcString)
str = self._moved__str__(*args, **kArgs)
sReentry -= 1 sReentry -= 1
return str
oldExcepthook = None
# store these values here so that Task.py can always reliably access these values
# from its main exception handler
wantVariableDump = False
dumpOnExceptionInit = False
def _excepthookDumpVars(eType, eValue, traceback):
s = 'DUMPING STACK FRAME VARIABLES'
tb = traceback
#import pdb;pdb.set_trace()
foundRun = False
while tb is not None:
frame = tb.tb_frame
code = frame.f_code
tb = tb.tb_next
# skip everything before the 'run' method, those frames have lots of
# not-useful information
if not foundRun:
if code.co_name == 'run':
foundRun = True
else:
continue
s += '\n File "%s", line %s, in %s' % (
code.co_filename, frame.f_lineno, code.co_name)
for name, val in frame.f_locals.iteritems():
r = fastRepr(val)
if type(r) is types.StringType:
r = r.replace('\n', '\\n')
s += '\n %s=%s' % (name, r)
s += '\n'
notify.info(s)
oldExcepthook(eType, eValue, traceback)
def install(): def install():
global oldExcepthook
global wantVariableDump
global dumpOnExceptionInit
wantVariableDump = True
dumpOnExceptionInit = config.GetBool('variable-dump-on-exception-init', 0)
if dumpOnExceptionInit:
# this mode doesn't completely work because exception objects
# thrown by the interpreter don't get created until the
# stack has been unwound and an except block has been reached
if not hasattr(Exception, '_moved__init__'): if not hasattr(Exception, '_moved__init__'):
Exception._moved__init__ = Exception.__init__ Exception._moved__init__ = Exception.__init__
Exception.__init__ = _varDump__init__ Exception.__init__ = _varDump__init__
Exception._moved__str__ = Exception.__str__ else:
Exception.__str__ = _varDump__str__ if sys.excepthook is not _excepthookDumpVars:
oldExcepthook = sys.excepthook
sys.excepthook = _excepthookDumpVars

View File

@ -2244,11 +2244,29 @@ def gcDebugOn():
import gc import gc
return (gc.get_debug() & gc.DEBUG_SAVEALL) == gc.DEBUG_SAVEALL return (gc.get_debug() & gc.DEBUG_SAVEALL) == gc.DEBUG_SAVEALL
# base class for all Panda C++ objects
# libdtoolconfig doesn't seem to have this, grab it off of PandaNode
dtoolSuperBase = None
def _getDtoolSuperBase():
global dtoolSuperBase
from pandac.PandaModules import PandaNode
dtoolSuperBase = PandaNode('').__class__.__bases__[0].__bases__[0].__bases__[0]
def safeRepr(obj): def safeRepr(obj):
global dtoolSuperBase
if dtoolSuperBase is None:
_getDtoolSuperBase()
if isinstance(obj, dtoolSuperBase):
# repr of C++ object could crash, particularly if the object has been deleted
return '<%s.%s instance at %s>' % (
obj.__class__.__module__, obj.__class__.__name__, hex(id(obj)))
try: try:
return repr(obj) return repr(obj)
except: except:
return '<** FAILED REPR OF %s **>' % obj.__class__.__name__ return '<** FAILED REPR OF %s instance at %s **>' % (obj.__class__.__name__, hex(id(obj)))
def fastRepr(obj, maxLen=200, strFactor=10, _visitedIds=None): def fastRepr(obj, maxLen=200, strFactor=10, _visitedIds=None):
""" caps the length of iterable types, so very large objects will print faster. """ caps the length of iterable types, so very large objects will print faster.
@ -2302,7 +2320,10 @@ def fastRepr(obj, maxLen=200, strFactor=10, _visitedIds=None):
else: else:
return safeRepr(obj) return safeRepr(obj)
else: else:
return safeRepr(obj) r = safeRepr(obj)
if len(r) > maxLen:
r = r[:maxLen]
return r
except: except:
return '<** FAILED REPR OF %s **>' % obj.__class__.__name__ return '<** FAILED REPR OF %s **>' % obj.__class__.__name__
@ -2445,11 +2466,20 @@ class RefCounter:
return result return result
def itype(obj): def itype(obj):
# version of type that gives more complete information about instance types
global dtoolSuperBase
t = type(obj) t = type(obj)
if t is types.InstanceType: if t is types.InstanceType:
return '%s of <class %s>>' % (repr(types.InstanceType)[:-1], return '%s of <class %s>>' % (repr(types.InstanceType)[:-1],
str(obj.__class__)) str(obj.__class__))
else: else:
# C++ object instances appear to be types via type()
# check if this is a C++ object
if dtoolSuperBase is None:
_getDtoolSuperBase()
if isinstance(obj, dtoolSuperBase):
return '%s of %s>' % (repr(types.InstanceType)[:-1],
str(obj.__class__))
return t return t
def deeptype(obj, maxLen=100, _visitedIds=None): def deeptype(obj, maxLen=100, _visitedIds=None):

View File

@ -35,6 +35,7 @@ import Loader
import time import time
from direct.fsm import ClassicFSM from direct.fsm import ClassicFSM
from direct.fsm import State from direct.fsm import State
from direct.showbase import ExceptionVarDump
import DirectObject import DirectObject
import SfxPlayer import SfxPlayer
if __debug__: if __debug__:
@ -69,6 +70,8 @@ class ShowBase(DirectObject.DirectObject):
notify = directNotify.newCategory("ShowBase") notify = directNotify.newCategory("ShowBase")
def __init__(self): def __init__(self):
if config.GetBool('want-variable-dump', 1):
ExceptionVarDump.install()
# Locate the directory containing the main program # Locate the directory containing the main program
maindir=os.path.abspath(sys.path[0]) maindir=os.path.abspath(sys.path[0])

View File

@ -14,6 +14,7 @@ from pandac.libpandaexpressModules import *
from direct.directnotify.DirectNotifyGlobal import * from direct.directnotify.DirectNotifyGlobal import *
from direct.showbase.PythonUtil import * from direct.showbase.PythonUtil import *
from direct.showbase.MessengerGlobal import * from direct.showbase.MessengerGlobal import *
from direct.showbase import ExceptionVarDump
import time import time
import fnmatch import fnmatch
import string import string
@ -981,6 +982,15 @@ class TaskManager:
self.stop() self.stop()
else: else:
raise raise
except Exception, e:
if self.extendedExceptions:
self.stop()
print_exc_plus()
else:
if (ExceptionVarDump.wantVariableDump and
ExceptionVarDump.dumpOnExceptionInit):
ExceptionVarDump._varDump__print(e)
raise
except: except:
if self.extendedExceptions: if self.extendedExceptions:
self.stop() self.stop()