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
23 LEVEL_FATAL
= logging
.FATAL
24 LEVEL_ERROR
= logging
.ERROR
25 LEVEL_WARN
= logging
.WARN
26 LEVEL_INFO
= logging
.INFO
27 LEVEL_DEBUG
= logging
.DEBUG
29 EXCEPTION_INFO
= 'exceptionInfo'
34 def initLogging(mode
):
36 if (mode
== LOG_MODE_IDE
):
37 configFile
= os
.getenv("AG_LOGCONFIG_IDE")
38 elif (mode
== LOG_MODE_TESTRUN
):
39 configFile
= os
.getenv("AG_LOGCONFIG_TESTRUN")
41 configFile
= os
.getenv("AG_LOGCONFIG_RUN")
42 if ((configFile
== None) or not os
.path
.exists(configFile
)):
43 if (mode
== LOG_MODE_IDE
):
45 elif (mode
== LOG_MODE_TESTRUN
):
46 configFile
= "TestRunLog"
49 configFile
= sysutils
.mainModuleDir
+ "/py" + configFile
+ ".ini"
50 if (os
.path
.exists(configFile
)):
51 fileConfig(configFile
)
53 defaultStream
= sys
.stderr
54 if (mode
== LOG_MODE_RUN
):
55 defaultStream
= sys
.stdout
56 handler
= logging
.StreamHandler(defaultStream
)
57 handler
.setLevel(logging
.INFO
)
58 handler
.setFormatter(logging
.Formatter("%(asctime)s %(name)s %(levelname)s: %(message)s"))
59 logging
.getLogger().addHandler(handler
)
62 ag_debugLogger
= logging
.getLogger("activegrid.debug")
64 def log(logger
, level
, msg
, *params
):
66 logger
= ag_debugLogger
67 apply(logger
.log
, (level
, msg
) + params
)
69 def fatal(logger
, msg
, *params
):
70 apply(logger
.fatal
, (msg
,) + params
)
72 def error(logger
, msg
, *params
):
73 apply(logger
.error
, (msg
,) + params
)
75 def warn(logger
, msg
, *params
):
76 apply(logger
.warn
, (msg
,) + params
)
78 def info(logger
, msg
, *params
):
79 apply(logger
.info
, (msg
,) + params
)
81 def debug(logger
, msg
, *params
):
83 logger
= ag_debugLogger
84 apply(logger
.debug
, (msg
,) + params
)
86 def setLevelFatal(logger
):
87 logger
.setLevel(LEVEL_FATAL
)
89 def setLevelError(logger
):
90 logger
.setLevel(LEVEL_ERROR
)
92 def setLevelWarn(logger
):
93 logger
.setLevel(LEVEL_WARN
)
95 def setLevelInfo(logger
):
96 logger
.setLevel(LEVEL_INFO
)
98 def setLevelDebug(logger
):
99 logger
.setLevel(LEVEL_DEBUG
)
101 def isEnabledForError(logger
):
102 return logger
.isEnabledFor(LEVEL_ERROR
)
104 def isEnabledForWarn(logger
):
105 return logger
.isEnabledFor(LEVEL_WARN
)
107 def isEnabledForInfo(logger
):
108 return logger
.isEnabledFor(LEVEL_INFO
)
110 def isEnabledForDebug(logger
):
111 return logger
.isEnabledFor(LEVEL_DEBUG
)
114 TEST_MODE_DETERMINISTIC
= 1
115 TEST_MODE_NON_DETERMINISTIC
= 2
118 agTestMode
= TEST_MODE_NONE
120 def setTestMode(mode
):
128 def testMode(normalObj
, testObj
=None, nonDeterministicObj
=None):
129 testMode
= getTestMode()
130 if testMode
> TEST_MODE_NONE
:
131 if ((nonDeterministicObj
!= None) and (testMode
== TEST_MODE_NON_DETERMINISTIC
)):
132 return nonDeterministicObj
136 pythonFileRefPattern
= asString(r
'(?<=File ")[^"]*(#[^#]*")(, line )[0-9]*')
137 phpFileRefPattern
= asString(r
'( in ).*#([^#]*#[^ ]*)(?= on line )')
138 pathSepPattern
= os
.sep
139 if (pathSepPattern
== "\\"):
140 pathSepPattern
= "\\\\"
141 pythonFileRefPattern
= pythonFileRefPattern
.replace("#", pathSepPattern
)
142 pythonFileRefPattern
= re
.compile(pythonFileRefPattern
)
143 phpFileRefPattern
= phpFileRefPattern
.replace("#", pathSepPattern
)
144 phpFileRefPattern
= re
.compile(phpFileRefPattern
)
146 def removeFileRefs(str):
147 str = pythonFileRefPattern
.sub(_fileNameReplacement
, str)
148 str = phpFileRefPattern
.sub(_fileNameReplacementPHP
, str)
151 def removePHPFileRefs(str):
152 str = phpFileRefPattern
.sub(_fileNameReplacementPHP
, str)
155 def _fileNameReplacement(match
):
156 return "...%s" % match
.group(1).replace(os
.sep
, "/")
158 def _fileNameReplacementPHP(match
):
159 return "%s...%s" % (match
.group(1), match
.group(2).replace(os
.sep
, "/"))
161 def formatTraceback(tb
=None):
163 extype
, val
, tb
= sys
.exc_info()
164 tbs
= "\n" + "".join(traceback
.format_tb(tb
))
167 def formatExceptionCause(cause
, stacktrace
=False):
172 tbs
= formatTraceback()
173 return "Caused by %s.%s: %s%s" % (cause
.__module
__, cause
.__class
__.__name
__, str(cause
), tbs
)
175 def addExceptionInfo(e
, key
, value
):
176 if not hasattr(e
, EXCEPTION_INFO
):
178 setattr(e
, EXCEPTION_INFO
, {})
180 return # Make sure we still report the real exception even if we can't add the extra info
181 if not e
.exceptionInfo
.has_key(key
): # Never overwrite exception info since we assume earlier info is more specific
182 e
.exceptionInfo
[key
] = value
184 def reportException(out
=None, stacktrace
=False, diffable
=False, exception
=None):
185 exstr
= exceptionToString(exception
, stacktrace
, diffable
)
191 def exceptionToString(exception
=None, stacktrace
=False, diffable
=False):
192 if (exception
== None):
193 extype
, val
, t
= sys
.exc_info()
195 extype
= objutils
.typeToString(exception
)
198 e
,v
,t
= sys
.exc_info()
200 exstr
= removeFileRefs(str(val
))
203 if hasattr(val
, EXCEPTION_INFO
):
205 for infoKey
, infoValue
in getattr(val
, EXCEPTION_INFO
).items():
207 prefix
= " EXTRA INFO:"
211 exstr
+= ("%s %s=%s" % (prefix
, infoKey
, infoValue
))
212 result
= "Got Exception = %s: %s" % (extype
, exstr
)
214 fmt
= traceback
.format_exception(extype
, val
, t
)
217 s
= removeFileRefs(s
)
218 result
= result
+ "\n" + s
221 def fileConfig(fname
, defaults
=None):
223 This is copied from logging.config so that we could fix the class lookup of
224 handlers. Previously handlers had to be defined in logging.handlers and we
225 need to be able to define our own.
227 import ConfigParser
, string
229 cp
= ConfigParser
.ConfigParser(defaults
)
230 if hasattr(cp
, 'readfp') and hasattr(fname
, 'readline'):
234 #first, do the formatters...
235 flist
= cp
.get("formatters", "keys")
237 flist
= string
.split(flist
, ",")
240 sectname
= "formatter_%s" % form
241 opts
= cp
.options(sectname
)
243 fs
= cp
.get(sectname
, "format", 1)
246 if "datefmt" in opts
:
247 dfs
= cp
.get(sectname
, "datefmt", 1)
250 f
= logging
.Formatter(fs
, dfs
)
252 #next, do the handlers...
254 logging
._acquireLock
()
257 #first, lose the existing handlers...
258 logging
._handlers
.clear()
259 #now set up the new ones...
260 hlist
= cp
.get("handlers", "keys")
262 hlist
= string
.split(hlist
, ",")
264 fixups
= [] #for inter-handler references
267 sectname
= "handler_%s" % hand
268 classname
= cp
.get(sectname
, "class")
269 opts
= cp
.options(sectname
)
270 if "formatter" in opts
:
271 fmt
= cp
.get(sectname
, "formatter")
276 klass
= eval(classname
, vars(logging
))
280 klass
= objutils
.classForName(classname
)
281 args
= cp
.get(sectname
, "args")
282 args
= eval(args
, vars(logging
))
283 h
= apply(klass
, args
)
285 level
= cp
.get(sectname
, "level")
286 h
.setLevel(logging
._levelNames
[level
])
288 h
.setFormatter(formatters
[fmt
])
289 #temporary hack for FileHandler and MemoryHandler.
290 if klass
== logging
.handlers
.MemoryHandler
:
292 target
= cp
.get(sectname
,"target")
295 if len(target
): #the target handler may not be loaded yet, so keep for later...
296 fixups
.append((h
, target
))
298 ## except Exception, e: #if an error occurs when instantiating a handler, too bad
299 ## pass #this could happen e.g. because of lack of privileges
300 #now all handlers are loaded, fixup inter-handler references...
304 h
.setTarget(handlers
[t
])
305 #at last, the loggers...first the root...
306 llist
= cp
.get("loggers", "keys")
307 llist
= string
.split(llist
, ",")
309 sectname
= "logger_root"
312 opts
= cp
.options(sectname
)
314 level
= cp
.get(sectname
, "level")
315 log
.setLevel(logging
._levelNames
[level
])
316 for h
in root
.handlers
[:]:
317 root
.removeHandler(h
)
318 hlist
= cp
.get(sectname
, "handlers")
320 hlist
= string
.split(hlist
, ",")
322 log
.addHandler(handlers
[hand
])
323 #and now the others...
324 #we don't want to lose the existing loggers,
325 #since other threads may have pointers to them.
326 #existing is set to contain all existing loggers,
327 #and as we go through the new configuration we
328 #remove any which are configured. At the end,
329 #what's left in existing is the set of loggers
330 #which were in the previous configuration but
331 #which are not in the new configuration.
332 existing
= root
.manager
.loggerDict
.keys()
333 #now set up the new ones...
335 sectname
= "logger_%s" % log
336 qn
= cp
.get(sectname
, "qualname")
337 opts
= cp
.options(sectname
)
338 if "propagate" in opts
:
339 propagate
= cp
.getint(sectname
, "propagate")
342 logger
= logging
.getLogger(qn
)
346 level
= cp
.get(sectname
, "level")
347 logger
.setLevel(logging
._levelNames
[level
])
348 for h
in logger
.handlers
[:]:
349 logger
.removeHandler(h
)
350 logger
.propagate
= propagate
352 hlist
= cp
.get(sectname
, "handlers")
354 hlist
= string
.split(hlist
, ",")
356 logger
.addHandler(handlers
[hand
])
357 #Disable any old loggers. There's no point deleting
358 #them as other threads may continue to hold references
359 #and by disabling them, you stop them doing any logging.
361 root
.manager
.loggerDict
[log
].disabled
= 1
364 ## ei = sys.exc_info()
365 ## traceback.print_exception(ei[0], ei[1], ei[2], None, sys.stderr)
368 logging
._releaseLock
()