Welcome, guest | Sign In | My Account | Store | Cart
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)
            
     ############################################################################  
   

History