import sys, traceback, string, os
from datetime import datetime
"""
XceptionHandler: Rev 4
Change Log:
04/2/2010 -Added option to allow for exception to be raised rather than
returned and still have logging and messaging options as well
04/2/2010 -Added option for overriding default logging by passing in a logging
object of the main project or parent class
04/6/2010 -Replace query builder with raw traceback dump return to allow more
code flexibility
INIT VARS:
DEBUG bool Turn ON/OFF Debug Messages
LOG_FILE str Name of Logfile default to XceptLog.txt
LOG_TABLE str Name of LOGGING DB TABLE if used input query and data tuple
are generated for feeding into MySQLdb or SQLlite
MSG_TYPE str Detailed or Simple Versions of Debug Messages
EXC_RETURN ref Indicate an exception has occured and will be returned
EXC_RAISE ref Indicates an exception occured and to raise it rather than return
EXC_RAW ref Indicate and exception occured and will return traceback dump
as a dict.
LOG_EVENTS bool Set default for logging can be overridden as needed in methods
"""
class XceptionHandler:
def __init__(self, DEBUG=False, LOG_FILE="XceptLog.txt", LOG_TABLE="",
LOG_PATH= os.path.abspath(os.curdir)+os.sep+"xLOGS"+os.sep,
MSG_TYPE="Detailed", EXC_RETURN=-1, EXC_RAW=-2, EXC_RAISE=-3,
LOG_OBJ=None, LOG_EVENTS=False):
self.xname = str(self.__class__).split(".")[1]
self.Debug = DEBUG
self.MSG_TYPE = MSG_TYPE
self.LOG_TABLE = LOG_TABLE
self.LOG_FILE = LOG_FILE
self.LOG_PATH = LOG_PATH
self.LOG_OBJ = LOG_OBJ
self.EXC_RETURN = EXC_RETURN
self.EXC_RAISE = EXC_RAISE
self.EXC_RAW = EXC_RAW
self.LOG_EVENTS = LOG_EVENTS
"""
Formatter for Debug Messages
vars:
ARGS dict
"""
def ReturnFormat(self, ARGS, CallType):
DetailedErr = ""
DetailedErr1 = """
--- EXCEPTION_ERROR ---
File : """+ARGS["filename"]
DetailedErr2 = """
Class : """+ARGS["classname"]
DetailedErr3 = """
: """+ARGS["methodname"]+"""
Line : """+ARGS["lineNumber"]+"""
DTS : """+str(datetime.now())+"""
Exception Type : """+ARGS["exc_type"]+"""
Exception Value: """+ARGS["exc_value"]+"""
Exception Msg : """+ARGS["exc_info"] +"""
------------------------
"""
SimpleErr = """
--- ERROR ---
ErrorType : """+ARGS["exc_type"]+"""
ErrorValue: """+ARGS["exc_value"]+"""
ErrorMsg : """+ARGS["exc_info"]+"""
------------------------
"""
if self.MSG_TYPE == "Detailed":
if CallType.find("Method") != -1:
DetailedErr = DetailedErr1+DetailedErr2+DetailedErr3
else:
DetailedErr = DetailedErr1+DetailedErr3
DetailedErr = DetailedErr.replace("", CallType)
return DetailedErr
else:
return SimpleErr
"""
Function exception handler
Not intended to be directly called from the function but rather via ProcessReturn
vars:
retval str
"""
def FunctionXHandler(self, retval):
myObject = sys.exc_info()[2]
myTraceBack = traceback.extract_tb(myObject)
fileName = myTraceBack[0][0]
lineNumber = str(myTraceBack[0][1])
functionName = myTraceBack[0][2]
className = " - "
ARGS = dict()
ARGS["filename"] = fileName
ARGS["classname"] = className
ARGS["methodname"] = functionName
ARGS["lineNumber"] = lineNumber
ARGS["exc_type"] = str(sys.exc_type)
ARGS["exc_value"] = str(sys.exc_value)
ARGS["exc_info"] = str(sys.exc_info()[0])
ARGS["Message"] = self.ReturnFormat(ARGS, "Function ")
return ARGS
"""
Class Method exception handler
Not intended to be directly called from the method but rather through ProcessReturn
vars:
className str Name of calling class
"""
def ClassXHandler(self, className):
myObject = sys.exc_info()[2]
myTraceBack = traceback.extract_tb(myObject)
fileName = myTraceBack[0][0]
lineNumber = str(myTraceBack[0][1])
methodName = myTraceBack[0][2]
ARGS = dict()
ARGS["filename"] = fileName
ARGS["Return"] = ARGS.get("Return", "EXCEPTION_ERROR")
ARGS["classname"] = className
ARGS["methodname"] = methodName
ARGS["lineNumber"] = lineNumber
ARGS["exc_type"] = str(sys.exc_type)
ARGS["exc_value"] = str(sys.exc_value)
ARGS["exc_info"] = str(sys.exc_info()[0])
ARGS["Message"] = self.ReturnFormat(ARGS, "Method ")
if className == self.xname:
print ARGS["Message"]
return ARGS
def ParseArgs(self, args):
try:
args = args[0]
retVal = None
logEvent= self.LOG_EVENTS
logMsg = ""
if len(args)== 3:
retVal=args[0]
if type(args[1]) == type(""):
logMsg = args[1]
logEvent = args[2]
elif type(args[1]) == type(bool()):
logEvent = args[1]
logMsg = args[2]
elif len(args) == 2:
retVal=args[0]
if type(args[1]) == type(""):
logMsg = args[1]
else:
logEvent = args[1]
elif len(args) == 1:
retVal=args[0]
return retVal, logEvent, logMsg
except:
return self.ClassXHandler(self.xname)
"""
Main Method for handling return values, determine if exception/error/good
and react accordingly
vars:
retVal dynamicType a -1 value indicates an exception
and will return -1 gracefully.
a -2 value indicates an exception
and will return the raw traceback elements
as a dict.
a -3 value indicates an exception
and will raise it.
everything else is passed through
className str name of calling class if called from a class
logEvent bool True = logging, False = no logging
2 = create DB query and data tuple
logMsg str Custom pass though message to be logged
"""
def ProcessReturn(self, className=None, *args):
retVal, logEvent, logMsg = self.ParseArgs(args)
ARGS = dict()
if retVal == self.EXC_RETURN or retVal == self.EXC_RAISE or retVal == self.EXC_RAW:
if className != None:
ARGS = self.ClassXHandler(className)
else:
ARGS = self.FunctionXHandler(retVal)
if logMsg !="":
ARGS["Message"] = logMsg
if self.Debug:
print ARGS["Message"]
if logEvent:
self.LogEvent(ARGS)
if retVal == self.EXC_RAISE:
raise
elif retVal == self.EXC_RAW:
return ARGS
return retVal
def LogEvent(self, ARGS):
try:
if self.LOG_OBJ != None:
#logging object
self.LOG_OBJ(ARGS["Message"])
elif self.LOG_OBJ == None:
#default log
LogPath = self.LOG_PATH+self.LOG_FILE
if not os.path.exists(LogPath):
os.mkdir(LogPath)
fp = open(LogPath, "a+")
fp.write(ARGS["Message"])
fp.close()
except:
return self.ClassXHandler(self.xname)
if __name__ == '__main__':
############################################################################
#Simple Setup To Show How To Reuse Your Already Instantiated Logging
#Xceptions.py to override the default internal log
import logging
logging.basicConfig(filename="ProjectLog.txt",level=logging.DEBUG)
Log_Object = logging.debug
##########################################################################
# Function Usage Example
XH =XceptionHandler(DEBUG=True, LOG_TABLE="DBLogTable",
LOG_OBJ=Log_Object, LOG_EVENTS=True)
def _Return(*args):
return XH.ProcessReturn(None, args)
def XampleFunction1():
try:
x = 2/0
return _Return(1, "SUCCESS")
except:
tb_dump = _Return(-2)
print tb_dump
return tb_dump
def XampleFunction2():
try:
x = 2/0
return _Return(1, "SUCCESS", False) #override LOG_EVENTS one time
except:
return _Return(-1)
def XampleFunction3():
try:
x = 2/1
return _Return(1, "SUCCESS")
except:
_Return(-3)
############################################################################
############################################################################
# Class Usage Example
class XampleClass(XceptionHandler):
def __init__(self):
self.name = str(self.__class__).split(".")[1]
XceptionHandler.__init__(self, DEBUG=True, LOG_EVENTS=False)
def _Return(self, *args):
return self.ProcessReturn(self.name, args)
def Test1(self):
try:
print x
return self._Return(1)
except:
return self._Return(-1)
def Test2(self):
try:
print z
return self._Return(True, "Success")
except:
return self._Return(-1, "FAIL", True)
def Test3(self):
try:
print w
return self._Return(True, "Success")
except:
return self._Return(-2, "FAIL returning traceback dump")
def Test4(self):
try:
print w
return self._Return(True, "Success")
except:
self._Return(-3)
############################################################################
XampleFunction1()
XampleFunction2()
XampleFunction3()
xc = XampleClass()
xc.Test1()
xc.Test2()
xc.Test3()
xc.Test4()