@@ -238,7 +238,7 @@ class LogRecord(object):
238238 information to be logged.
239239 """
240240 def __init__ (self , name , level , pathname , lineno ,
241- msg , args , exc_info , func = None ):
241+ msg , args , exc_info , func = None , sinfo = None ):
242242 """
243243 Initialize a logging record with interesting information.
244244 """
@@ -272,6 +272,7 @@ def __init__(self, name, level, pathname, lineno,
272272 self .module = "Unknown module"
273273 self .exc_info = exc_info
274274 self .exc_text = None # used to cache the traceback text
275+ self .stack_info = sinfo
275276 self .lineno = lineno
276277 self .funcName = func
277278 self .created = ct
@@ -515,6 +516,19 @@ def usesTime(self):
515516 def formatMessage (self , record ):
516517 return self ._style .format (record )
517518
519+ def formatStack (self , stack_info ):
520+ """
521+ This method is provided as an extension point for specialized
522+ formatting of stack information.
523+
524+ The input data is a string as returned from a call to
525+ :func:`traceback.print_stack`, but with the last trailing newline
526+ removed.
527+
528+ The base implementation just returns the value passed in.
529+ """
530+ return stack_info
531+
518532 def format (self , record ):
519533 """
520534 Format the specified record as text.
@@ -541,6 +555,10 @@ def format(self, record):
541555 if s [- 1 :] != "\n " :
542556 s = s + "\n "
543557 s = s + record .exc_text
558+ if record .stack_info :
559+ if s [- 1 :] != "\n " :
560+ s = s + "\n "
561+ s = s + self .formatStack (record .stack_info )
544562 return s
545563
546564#
@@ -1213,11 +1231,12 @@ def error(self, msg, *args, **kwargs):
12131231 if self .isEnabledFor (ERROR ):
12141232 self ._log (ERROR , msg , args , ** kwargs )
12151233
1216- def exception (self , msg , * args ):
1234+ def exception (self , msg , * args , ** kwargs ):
12171235 """
12181236 Convenience method for logging an ERROR with exception information.
12191237 """
1220- self .error (msg , exc_info = 1 , * args )
1238+ kwargs ['exc_info' ] = True
1239+ self .error (msg , * args , ** kwargs )
12211240
12221241 def critical (self , msg , * args , ** kwargs ):
12231242 """
@@ -1250,7 +1269,7 @@ def log(self, level, msg, *args, **kwargs):
12501269 if self .isEnabledFor (level ):
12511270 self ._log (level , msg , args , ** kwargs )
12521271
1253- def findCaller (self ):
1272+ def findCaller (self , stack_info = False ):
12541273 """
12551274 Find the stack frame of the caller so that we can note the source
12561275 file name, line number and function name.
@@ -1260,49 +1279,62 @@ def findCaller(self):
12601279 #IronPython isn't run with -X:Frames.
12611280 if f is not None :
12621281 f = f .f_back
1263- rv = "(unknown file)" , 0 , "(unknown function)"
1282+ rv = "(unknown file)" , 0 , "(unknown function)" , None
12641283 while hasattr (f , "f_code" ):
12651284 co = f .f_code
12661285 filename = os .path .normcase (co .co_filename )
12671286 if filename == _srcfile :
12681287 f = f .f_back
12691288 continue
1270- rv = (co .co_filename , f .f_lineno , co .co_name )
1289+ sinfo = None
1290+ if stack_info :
1291+ sio = io .StringIO ()
1292+ sio .write ('Stack (most recent call last):\n ' )
1293+ traceback .print_stack (f , file = sio )
1294+ sinfo = sio .getvalue ()
1295+ if sinfo [- 1 ] == '\n ' :
1296+ sinfo = sinfo [:- 1 ]
1297+ sio .close ()
1298+ rv = (co .co_filename , f .f_lineno , co .co_name , sinfo )
12711299 break
12721300 return rv
12731301
1274- def makeRecord (self , name , level , fn , lno , msg , args , exc_info , func = None , extra = None ):
1302+ def makeRecord (self , name , level , fn , lno , msg , args , exc_info ,
1303+ func = None , extra = None , sinfo = None ):
12751304 """
12761305 A factory method which can be overridden in subclasses to create
12771306 specialized LogRecords.
12781307 """
1279- rv = _logRecordClass (name , level , fn , lno , msg , args , exc_info , func )
1308+ rv = _logRecordClass (name , level , fn , lno , msg , args , exc_info , func ,
1309+ sinfo )
12801310 if extra is not None :
12811311 for key in extra :
12821312 if (key in ["message" , "asctime" ]) or (key in rv .__dict__ ):
12831313 raise KeyError ("Attempt to overwrite %r in LogRecord" % key )
12841314 rv .__dict__ [key ] = extra [key ]
12851315 return rv
12861316
1287- def _log (self , level , msg , args , exc_info = None , extra = None ):
1317+ def _log (self , level , msg , args , exc_info = None , extra = None , stack_info = False ):
12881318 """
12891319 Low-level logging routine which creates a LogRecord and then calls
12901320 all the handlers of this logger to handle the record.
12911321 """
1322+ sinfo = None
12921323 if _srcfile :
12931324 #IronPython doesn't track Python frames, so findCaller throws an
12941325 #exception on some versions of IronPython. We trap it here so that
12951326 #IronPython can use logging.
12961327 try :
1297- fn , lno , func = self .findCaller ()
1328+ fn , lno , func , sinfo = self .findCaller (stack_info )
12981329 except ValueError :
12991330 fn , lno , func = "(unknown file)" , 0 , "(unknown function)"
13001331 else :
13011332 fn , lno , func = "(unknown file)" , 0 , "(unknown function)"
13021333 if exc_info :
13031334 if not isinstance (exc_info , tuple ):
13041335 exc_info = sys .exc_info ()
1305- record = self .makeRecord (self .name , level , fn , lno , msg , args , exc_info , func , extra )
1336+ record = self .makeRecord (self .name , level , fn , lno , msg , args ,
1337+ exc_info , func , extra , sinfo )
13061338 self .handle (record )
13071339
13081340 def handle (self , record ):
@@ -1657,12 +1689,13 @@ def error(msg, *args, **kwargs):
16571689 basicConfig ()
16581690 root .error (msg , * args , ** kwargs )
16591691
1660- def exception (msg , * args ):
1692+ def exception (msg , * args , ** kwargs ):
16611693 """
16621694 Log a message with severity 'ERROR' on the root logger,
16631695 with exception information.
16641696 """
1665- error (msg , exc_info = 1 , * args )
1697+ kwargs ['exc_info' ] = True
1698+ error (msg , * args , ** kwargs )
16661699
16671700def warning (msg , * args , ** kwargs ):
16681701 """
0 commit comments