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 = """
<CALL_TYPE> : """+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("<CALL_TYPE>", 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()
Diff to Previous Revision
--- revision 4 2010-04-06 16:07:55
+++ revision 5 2010-04-06 20:40:05
@@ -2,9 +2,7 @@
from datetime import datetime
"""
-XceptionHandler: Rev 2
-Author: A.J. Mayorga
-
+XceptionHandler: Rev 4
Change Log:
@@ -14,51 +12,37 @@
04/2/2010 -Added option for overriding default logging by passing in a logging
object of the main project or parent class
-Features:
- - Simple tracking and debugging of exceptions/errors in code
- - Debug messages can be toggled on or off
- - Allows For automated logging of errors using:
- - Default builtin log
- - Reuse of parent class/project logging objects
- - Can automatically generate SQL Insert queries and data tuples for DB logging
- - Option for letting exceptions be raised or returned
- - Override of return with custom messages
- - Discerns if exception was raised by a class method or function call
- - Provides detailed or simple debug messages returning:
- - filename
- - class name/function name
- - method name
- - line number
- - exception type
- - exception value
- - Successful return pass through
- - Successful returns can be logged with custom messages
-
-
+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, SQLlite, etc
-
-MSG_TYPE str Detailed or Simple Versions of Debug Messages
-
-EXC_RETURN dynamic ref value that is passed to class to return on exception
-
-EXC_RAISE dynamic ref value that is passed to class to raise the caught exception
-
-LOG_OBJ logging object ref logging object (ala function pointer) that when set overrides
- default logging
+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_RAISE=-2, LOG_OBJ=None):
+ 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
@@ -69,6 +53,8 @@
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
"""
@@ -184,15 +170,17 @@
def ParseArgs(self, args):
try:
- args = args[0]
- retVal=None;logEvent=0;logMsg=""
+ 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(int()):
+ elif type(args[1]) == type(bool()):
logEvent = args[1]
logMsg = args[2]
elif len(args) == 2:
@@ -217,98 +205,66 @@
and react accordingly
vars:
retVal dynamicType a -1 value indicates an exception
- and will return gracefully.
+ 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 0 = logging, 1 = Write To Log File Only
+ 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)
-
- if retVal == self.EXC_RETURN or retVal == self.EXC_RAISE:
+
+ 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 self.Debug:
- if logMsg == "":
- print ARGS["Message"]
- else:
- print logMsg
-
- if logEvent == 1:
- self.LogEvent(logEvent, ARGS)
+
+ if logMsg !="":
+ ARGS["Message"] = logMsg
+
+ if self.Debug:
+ print ARGS["Message"]
+
+ if logEvent:
+ self.LogEvent(ARGS)
- if logEvent == 2:
- if ARGS["Message"] == "":
- ARGS = dict()
- ARGS["Message"] = logMsg
- self.LogEvent(logEvent, ARGS)
-
- if retVal == self.EXC_RAISE:
- raise
-
- else:
- if logMsg != "":
- ARGS = dict()
- ARGS["Message"] = logMsg
- self.LogEvent(logEvent, ARGS)
- if self.Debug:
- print logMsg
-
+ if retVal == self.EXC_RAISE:
+ raise
+ elif retVal == self.EXC_RAW:
+ return ARGS
+
return retVal
-
-
-
- def LogEvent(self, logEvent, ARGS):
- try:
- if self.LOG_OBJ != None:
+
+
+
+ def LogEvent(self, ARGS):
+ try:
+ if self.LOG_OBJ != None:
+ #logging object
self.LOG_OBJ(ARGS["Message"])
-
- else:
+
+
+ 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()
-
- if self.LOG_TABLE != "" and logEvent >= 2 :
- query = """INSERT INTO `"""+self.LOG_TABLE+"""` ("""
- data = list()
- itemCount = len(ARGS)
-
- for key, value in ARGS.iteritems():
- query += """`"""+key+"""`,"""
- data.append(value)
-
- data = tuple(data)
- query = query[:-1]+""") VALUES ("""
- for idx in range(itemCount):
- query += """ %s,"""
- query = query[:-1]+""")"""
-
- if self.Debug:
- print query
- print data
-
- return query,data
-
- elif self.LOG_TABLE == "" and logEvent >= 2:
- print "Cannot create query and data tuple, no LOG_TABLE specified"
- return False
- else:
- return True
-
except:
return self.ClassXHandler(self.xname)
@@ -323,20 +279,18 @@
############################################################################
#Simple Setup To Show How To Reuse Your Already Instantiated Logging
- #with Xceptions.py to override the default internal log
-
+ #Xceptions.py to override the default internal log
import logging
- LOG_FILENAME = 'ProjectLog.txt'
- logging.basicConfig(filename=LOG_FILENAME,level=logging.DEBUG)
+ logging.basicConfig(filename="ProjectLog.txt",level=logging.DEBUG)
Log_Object = logging.debug
-
-
- ############################################################################
- # Function Usage Example reusing parent project/class logging and demonstrating
- # added EXC_RAISE option test 1, EXC_RETURN option test 2, SUCCESS pass thru test 3
-
- XH =XceptionHandler(DEBUG=True, LOG_TABLE="someDBTable", LOG_OBJ=Log_Object)
+
+
+ ##########################################################################
+ # 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)
@@ -347,35 +301,36 @@
x = 2/0
return _Return(1, "SUCCESS")
except:
- return _Return(-2, 1)
-
+ tb_dump = _Return(-2)
+ print tb_dump
+ return tb_dump
+
def XampleFunction2():
try:
x = 2/0
- return _Return(1, "SUCCESS")
+ return _Return(1, "SUCCESS", False) #override LOG_EVENTS one time
except:
return _Return(-1)
def XampleFunction3():
try:
- x = 2/2
+ x = 2/1
return _Return(1, "SUCCESS")
except:
- return _Return(-1)
+ _Return(-3)
############################################################################
############################################################################
- # Class Usage Example using default internal logging and able to
- # generate DB tuples (query,data) and print DEBUG messages
+ # Class Usage Example
class XampleClass(XceptionHandler):
def __init__(self):
self.name = str(self.__class__).split(".")[1]
- XceptionHandler.__init__(self, DEBUG=True, LOG_TABLE="myLogTable")
+ XceptionHandler.__init__(self, DEBUG=True, LOG_EVENTS=False)
def _Return(self, *args):
return self.ProcessReturn(self.name, args)
@@ -392,21 +347,21 @@
print z
return self._Return(True, "Success")
except:
- return self._Return(-1, "FAIL", 2)
+ return self._Return(-1, "FAIL", True)
def Test3(self):
try:
print w
- return self._Return(True, "Success", 1)
+ return self._Return(True, "Success")
except:
- return self._Return(-1, "FAIL returning DB tuple", 2)
+ return self._Return(-2, "FAIL returning traceback dump")
def Test4(self):
try:
print w
- return self._Return(True, "Success", 1)
+ return self._Return(True, "Success")
except:
- return self._Return(-2)
+ self._Return(-3)
############################################################################