1 #---------------------------------------------------------------------------- 
   3 # Purpose:      Utilities to help with logging 
   9 # Copyright:    (c) 2005 ActiveGrid, Inc. 
  10 # License:      wxWindows License 
  11 #---------------------------------------------------------------------------- 
  19 from activegrid
.util
.lang 
import * 
  20 import activegrid
.util
.objutils 
as objutils
 
  21 import activegrid
.util
.sysutils 
as sysutils
 
  22 import activegrid
.util
.appdirs 
as appdirs
 
  24 LEVEL_FATAL 
= logging
.FATAL
 
  25 LEVEL_ERROR 
= logging
.ERROR
 
  26 LEVEL_WARN 
= logging
.WARN
 
  27 LEVEL_INFO 
= logging
.INFO
 
  28 LEVEL_DEBUG 
= logging
.DEBUG
 
  30 EXCEPTION_INFO 
= 'exceptionInfo' 
  31 loggingInitialized 
= False 
  36 def initLogging(mode
, force
=False): 
  37     global ag_debugLogger
, loggingInitialized
 
  38     if (force 
or not loggingInitialized
): 
  39         loggingInitialized 
= True 
  41         if (mode 
== LOG_MODE_IDE
): 
  42             configFile 
= os
.getenv("AG_LOGCONFIG_IDE") 
  43         elif (mode 
== LOG_MODE_TESTRUN
): 
  44             configFile 
= os
.getenv("AG_LOGCONFIG_PYTESTRUN") 
  46             configFile 
= os
.getenv("AG_LOGCONFIG_RUN") 
  47         if ((configFile 
== None) or not os
.path
.exists(configFile
)): 
  48             if (mode 
== LOG_MODE_IDE
): 
  50             elif (mode 
== LOG_MODE_TESTRUN
): 
  51                 configFile 
= "TestRunLog" 
  54             configFile 
= os
.path
.join(appdirs
.getSystemDir(appdirs
.AG_LOGS_DIR
), "py" + configFile 
+ ".ini") 
  55         if (os
.path
.exists(configFile
)): 
  56             print "Using logging configuration file: %s" % configFile
 
  57             fileConfig(configFile
) 
  59             print "*** Cannot find logging configuration file (%s) -- setting default logging level to WARN ***" % (configFile
) 
  60             defaultStream 
= sys
.stderr
 
  61             if (mode 
== LOG_MODE_RUN
): 
  62                 defaultStream 
= sys
.stdout
 
  63             handler 
= logging
.StreamHandler(defaultStream
) 
  64             handler
.setLevel(logging
.DEBUG
) 
  65             handler
.setFormatter(logging
.Formatter("%(asctime)s %(name)s %(levelname)s: %(message)s")) 
  66             logging
.getLogger().addHandler(handler
) 
  67             logging
.getLogger().setLevel(logging
.WARN
) 
  68         ag_debugLogger 
= logging
.getLogger("activegrid.debug") 
  69         ag_debugLogger
.setLevel(logging
.DEBUG
) 
  72 ag_debugLogger 
= logging
.getLogger("activegrid.debug") 
  74 def log(logger
, level
, msg
, *params
): 
  76         logger 
= ag_debugLogger
 
  77     apply(logger
.log
, (level
, msg
) + params
) 
  79 def fatal(logger
, msg
, *params
): 
  80     apply(logger
.fatal
, (msg
,) + params
) 
  82 def error(logger
, msg
, *params
): 
  83     apply(logger
.error
, (msg
,) + params
) 
  85 def warn(logger
, msg
, *params
): 
  86     apply(logger
.warn
, (msg
,) + params
) 
  88 def info(logger
, msg
, *params
): 
  89     apply(logger
.info
, (msg
,) + params
) 
  91 def debug(logger
, msg
, *params
): 
  93         logger 
= ag_debugLogger
 
  94     apply(logger
.debug
, (msg
,) + params
) 
  96 def setLevelFatal(logger
): 
  97     logger
.setLevel(LEVEL_FATAL
) 
  99 def setLevelError(logger
): 
 100     logger
.setLevel(LEVEL_ERROR
) 
 102 def setLevelWarn(logger
): 
 103     logger
.setLevel(LEVEL_WARN
) 
 105 def setLevelInfo(logger
): 
 106     logger
.setLevel(LEVEL_INFO
) 
 108 def setLevelDebug(logger
): 
 109     logger
.setLevel(LEVEL_DEBUG
) 
 111 def isEnabledForError(logger
): 
 112     return logger
.isEnabledFor(LEVEL_ERROR
) 
 114 def isEnabledForWarn(logger
): 
 115     return logger
.isEnabledFor(LEVEL_WARN
) 
 117 def isEnabledForInfo(logger
): 
 118     return logger
.isEnabledFor(LEVEL_INFO
) 
 120 def isEnabledForDebug(logger
): 
 121     return logger
.isEnabledFor(LEVEL_DEBUG
) 
 124 TEST_MODE_DETERMINISTIC 
= 1 
 125 TEST_MODE_NON_DETERMINISTIC 
= 2 
 128 agTestMode 
= TEST_MODE_NONE
 
 130 def setTestMode(mode
): 
 138 def testMode(normalObj
, testObj
=None, nonDeterministicObj
=None): 
 139     testMode 
= getTestMode() 
 140     if testMode 
> TEST_MODE_NONE
: 
 141         if ((nonDeterministicObj 
!= None) and (testMode 
== TEST_MODE_NON_DETERMINISTIC
)): 
 142             return nonDeterministicObj
 
 146 pythonFileRefPattern 
= asString(r
'(?<=File ")[^"]*(#[^#]*")(, line )[0-9]*') 
 147 phpFileRefPattern 
= asString(r
'( in ).*#([^#]*#[^ ]*)(?= on line )') 
 148 pathSepPattern 
= os
.sep
 
 149 if (pathSepPattern 
== "\\"): 
 150     pathSepPattern 
= "\\\\" 
 151 pythonFileRefPattern 
= pythonFileRefPattern
.replace("#", pathSepPattern
) 
 152 pythonFileRefPattern 
= re
.compile(pythonFileRefPattern
) 
 153 phpFileRefPattern 
= phpFileRefPattern
.replace("#", pathSepPattern
) 
 154 phpFileRefPattern 
= re
.compile(phpFileRefPattern
) 
 156 def removeFileRefs(str): 
 157     str = pythonFileRefPattern
.sub(_fileNameReplacement
, str) 
 158     str = phpFileRefPattern
.sub(_fileNameReplacementPHP
, str) 
 161 def removePHPFileRefs(str): 
 162     str = phpFileRefPattern
.sub(_fileNameReplacementPHP
, str) 
 165 def _fileNameReplacement(match
): 
 166     return "...%s" % match
.group(1).replace(os
.sep
, "/") 
 168 def _fileNameReplacementPHP(match
): 
 169     return "%s...%s" % (match
.group(1), match
.group(2).replace(os
.sep
, "/")) 
 171 def formatTraceback(tb
=None): 
 173         extype
, val
, tb 
= sys
.exc_info() 
 174     tbs 
= "\n" + "".join(traceback
.format_tb(tb
)) 
 177 def formatExceptionCause(cause
, stacktrace
=False): 
 182         tbs 
= formatTraceback() 
 183     return "Caused by %s.%s: %s%s" % (cause
.__module
__, cause
.__class
__.__name
__, str(cause
), tbs
) 
 185 def addExceptionInfo(e
, key
, value
): 
 186     if not hasattr(e
, EXCEPTION_INFO
): 
 188             setattr(e
, EXCEPTION_INFO
, {}) 
 190             return # Make sure we still report the real exception even if we can't add the extra info 
 191     if not e
.exceptionInfo
.has_key(key
): # Never overwrite exception info since we assume earlier info is more specific 
 192         e
.exceptionInfo
[key
] = value
 
 194 def reportException(exception
, out
=None, stacktrace
=False, diffable
=False): 
 195     exstr 
= exceptionToString(exception
, stacktrace
, diffable
) 
 201 def exceptionToString(exception
, stacktrace
=False, diffable
=False): 
 202     extype 
= objutils
.typeToString(exception
) 
 205         e
,v
,t 
= sys
.exc_info() 
 207         exstr 
= removeFileRefs(str(val
)) 
 210     if hasattr(val
, EXCEPTION_INFO
): 
 212         for infoKey
, infoValue 
in getattr(val
, EXCEPTION_INFO
).items(): 
 214                 prefix 
= " EXTRA INFO:" 
 218             exstr 
+= ("%s %s=%s" % (prefix
, infoKey
, infoValue
)) 
 219     result 
= "Got Exception = %s: %s" % (extype
, exstr
) 
 221         fmt 
= traceback
.format_exception(extype
, val
, t
) 
 224                 s 
= removeFileRefs(s
) 
 225             result 
= result 
+ "\n" + s
 
 228 def fileConfig(fname
, defaults
=None): 
 230     This is copied from logging.config so that we could fix the class lookup of 
 231     handlers.  Previously handlers had to be defined in logging.handlers and we 
 232     need to be able to define our own. 
 234     import ConfigParser
, string
 
 236     cp 
= ConfigParser
.ConfigParser(defaults
) 
 237     if hasattr(cp
, 'readfp') and hasattr(fname
, 'readline'): 
 241     #first, do the formatters... 
 242     flist 
= cp
.get("formatters", "keys") 
 244         flist 
= string
.split(flist
, ",") 
 247             sectname 
= "formatter_%s" % form
 
 248             opts 
= cp
.options(sectname
) 
 250                 fs 
= cp
.get(sectname
, "format", 1) 
 253             if "datefmt" in opts
: 
 254                 dfs 
= cp
.get(sectname
, "datefmt", 1) 
 257             f 
= logging
.Formatter(fs
, dfs
) 
 259     #next, do the handlers... 
 261     logging
._acquireLock
() 
 264             #first, lose the existing handlers... 
 265             logging
._handlers
.clear() 
 266             #now set up the new ones... 
 267             hlist 
= cp
.get("handlers", "keys") 
 269                 hlist 
= string
.split(hlist
, ",") 
 271                 fixups 
= [] #for inter-handler references 
 274                         sectname 
= "handler_%s" % hand
 
 275                         classname 
= cp
.get(sectname
, "class") 
 276                         opts 
= cp
.options(sectname
) 
 277                         if "formatter" in opts
: 
 278                             fmt 
= cp
.get(sectname
, "formatter") 
 283                             klass 
= eval(classname
, vars(logging
)) 
 287                             klass 
= objutils
.classForName(classname
) 
 288                         args 
= cp
.get(sectname
, "args") 
 289                         args 
= eval(args
, vars(logging
)) 
 290                         h 
= apply(klass
, args
) 
 292                             level 
= cp
.get(sectname
, "level") 
 293                             h
.setLevel(logging
._levelNames
[level
]) 
 295                             h
.setFormatter(formatters
[fmt
]) 
 296                         #temporary hack for FileHandler and MemoryHandler. 
 297                         if klass 
== logging
.handlers
.MemoryHandler
: 
 299                                 target 
= cp
.get(sectname
,"target") 
 302                             if len(target
): #the target handler may not be loaded yet, so keep for later... 
 303                                 fixups
.append((h
, target
)) 
 305 ##                    except Exception, e:     #if an error occurs when instantiating a handler, too bad 
 306 ##                        pass    #this could happen e.g. because of lack of privileges 
 307                 #now all handlers are loaded, fixup inter-handler references... 
 311                     h
.setTarget(handlers
[t
]) 
 312             #at last, the loggers...first the root... 
 313             llist 
= cp
.get("loggers", "keys") 
 314             llist 
= string
.split(llist
, ",") 
 316             sectname 
= "logger_root" 
 319             opts 
= cp
.options(sectname
) 
 321                 level 
= cp
.get(sectname
, "level") 
 322                 log
.setLevel(logging
._levelNames
[level
]) 
 323             for h 
in root
.handlers
[:]: 
 324                 root
.removeHandler(h
) 
 325             hlist 
= cp
.get(sectname
, "handlers") 
 327                 hlist 
= string
.split(hlist
, ",") 
 329                     log
.addHandler(handlers
[hand
]) 
 330             #and now the others... 
 331             #we don't want to lose the existing loggers, 
 332             #since other threads may have pointers to them. 
 333             #existing is set to contain all existing loggers, 
 334             #and as we go through the new configuration we 
 335             #remove any which are configured. At the end, 
 336             #what's left in existing is the set of loggers 
 337             #which were in the previous configuration but 
 338             #which are not in the new configuration. 
 339             existing 
= root
.manager
.loggerDict
.keys() 
 340             #now set up the new ones... 
 342                 sectname 
= "logger_%s" % log
 
 343                 qn 
= cp
.get(sectname
, "qualname") 
 344                 opts 
= cp
.options(sectname
) 
 345                 if "propagate" in opts
: 
 346                     propagate 
= cp
.getint(sectname
, "propagate") 
 349                 logger 
= logging
.getLogger(qn
) 
 353                     level 
= cp
.get(sectname
, "level") 
 354                     logger
.setLevel(logging
._levelNames
[level
]) 
 355                 for h 
in logger
.handlers
[:]: 
 356                     logger
.removeHandler(h
) 
 357                 logger
.propagate 
= propagate
 
 359                 hlist 
= cp
.get(sectname
, "handlers") 
 361                     hlist 
= string
.split(hlist
, ",") 
 363                         logger
.addHandler(handlers
[hand
]) 
 364             #Disable any old loggers. There's no point deleting 
 365             #them as other threads may continue to hold references 
 366             #and by disabling them, you stop them doing any logging. 
 368                 root
.manager
.loggerDict
[log
].disabled 
= 1 
 371 ##            ei = sys.exc_info() 
 372 ##            traceback.print_exception(ei[0], ei[1], ei[2], None, sys.stderr) 
 375         logging
._releaseLock
()