Kaydet (Commit) 02a8f9e9 authored tarafından Vinay Sajip's avatar Vinay Sajip

Closes #20537: logging methods now accept an exception instance as well as a…

Closes #20537: logging methods now accept an exception instance as well as a Boolean value or exception tuple. Thanks to Yury Selivanov for the patch.
üst 4ff91eb5
...@@ -155,11 +155,13 @@ is the module's name in the Python package namespace. ...@@ -155,11 +155,13 @@ is the module's name in the Python package namespace.
*msg* using the string formatting operator. (Note that this means that you can *msg* using the string formatting operator. (Note that this means that you can
use keywords in the format string, together with a single dictionary argument.) use keywords in the format string, together with a single dictionary argument.)
There are three keyword arguments in *kwargs* which are inspected: *exc_info* There are three keyword arguments in *kwargs* which are inspected:
which, if it does not evaluate as false, causes exception information to be *exc_info*, *stack_info*, and *extra*.
If *exc_info* does not evaluate as false, it causes exception information to be
added to the logging message. If an exception tuple (in the format returned by added to the logging message. If an exception tuple (in the format returned by
:func:`sys.exc_info`) is provided, it is used; otherwise, :func:`sys.exc_info` :func:`sys.exc_info`) or an exception instance is provided, it is used;
is called to get the exception information. otherwise, :func:`sys.exc_info` is called to get the exception information.
The second optional keyword argument is *stack_info*, which defaults to The second optional keyword argument is *stack_info*, which defaults to
``False``. If true, stack information is added to the logging ``False``. If true, stack information is added to the logging
...@@ -216,6 +218,9 @@ is the module's name in the Python package namespace. ...@@ -216,6 +218,9 @@ is the module's name in the Python package namespace.
.. versionadded:: 3.2 .. versionadded:: 3.2
The *stack_info* parameter was added. The *stack_info* parameter was added.
.. versionchanged:: 3.5
The *exc_info* parameter can now accept exception instances.
.. method:: Logger.info(msg, *args, **kwargs) .. method:: Logger.info(msg, *args, **kwargs)
......
...@@ -1302,12 +1302,11 @@ class Logger(Filterer): ...@@ -1302,12 +1302,11 @@ class Logger(Filterer):
if self.isEnabledFor(ERROR): if self.isEnabledFor(ERROR):
self._log(ERROR, msg, args, **kwargs) self._log(ERROR, msg, args, **kwargs)
def exception(self, msg, *args, **kwargs): def exception(self, msg, *args, exc_info=True, **kwargs):
""" """
Convenience method for logging an ERROR with exception information. Convenience method for logging an ERROR with exception information.
""" """
kwargs['exc_info'] = True self.error(msg, *args, exc_info=exc_info, **kwargs)
self.error(msg, *args, **kwargs)
def critical(self, msg, *args, **kwargs): def critical(self, msg, *args, **kwargs):
""" """
...@@ -1402,7 +1401,9 @@ class Logger(Filterer): ...@@ -1402,7 +1401,9 @@ class Logger(Filterer):
else: # pragma: no cover else: # pragma: no cover
fn, lno, func = "(unknown file)", 0, "(unknown function)" fn, lno, func = "(unknown file)", 0, "(unknown function)"
if exc_info: if exc_info:
if not isinstance(exc_info, tuple): if isinstance(exc_info, BaseException):
exc_info = (type(exc_info), exc_info, exc_info.__traceback__)
elif not isinstance(exc_info, tuple):
exc_info = sys.exc_info() exc_info = sys.exc_info()
record = self.makeRecord(self.name, level, fn, lno, msg, args, record = self.makeRecord(self.name, level, fn, lno, msg, args,
exc_info, func, extra, sinfo) exc_info, func, extra, sinfo)
...@@ -1612,12 +1613,11 @@ class LoggerAdapter(object): ...@@ -1612,12 +1613,11 @@ class LoggerAdapter(object):
""" """
self.log(ERROR, msg, *args, **kwargs) self.log(ERROR, msg, *args, **kwargs)
def exception(self, msg, *args, **kwargs): def exception(self, msg, *args, exc_info=True, **kwargs):
""" """
Delegate an exception call to the underlying logger. Delegate an exception call to the underlying logger.
""" """
kwargs["exc_info"] = True self.log(ERROR, msg, *args, exc_info=exc_info, **kwargs)
self.log(ERROR, msg, *args, **kwargs)
def critical(self, msg, *args, **kwargs): def critical(self, msg, *args, **kwargs):
""" """
...@@ -1796,14 +1796,13 @@ def error(msg, *args, **kwargs): ...@@ -1796,14 +1796,13 @@ def error(msg, *args, **kwargs):
basicConfig() basicConfig()
root.error(msg, *args, **kwargs) root.error(msg, *args, **kwargs)
def exception(msg, *args, **kwargs): def exception(msg, *args, exc_info=True, **kwargs):
""" """
Log a message with severity 'ERROR' on the root logger, with exception Log a message with severity 'ERROR' on the root logger, with exception
information. If the logger has no handlers, basicConfig() is called to add information. If the logger has no handlers, basicConfig() is called to add
a console handler with a pre-defined format. a console handler with a pre-defined format.
""" """
kwargs['exc_info'] = True error(msg, *args, exc_info=exc_info, **kwargs)
error(msg, *args, **kwargs)
def warning(msg, *args, **kwargs): def warning(msg, *args, **kwargs):
""" """
......
...@@ -3712,6 +3712,19 @@ class LoggerAdapterTest(unittest.TestCase): ...@@ -3712,6 +3712,19 @@ class LoggerAdapterTest(unittest.TestCase):
self.assertEqual(record.exc_info, self.assertEqual(record.exc_info,
(exc.__class__, exc, exc.__traceback__)) (exc.__class__, exc, exc.__traceback__))
def test_exception_excinfo(self):
try:
1 / 0
except ZeroDivisionError as e:
exc = e
self.adapter.exception('exc_info test', exc_info=exc)
self.assertEqual(len(self.recording.records), 1)
record = self.recording.records[0]
self.assertEqual(record.exc_info,
(exc.__class__, exc, exc.__traceback__))
def test_critical(self): def test_critical(self):
msg = 'critical test! %r' msg = 'critical test! %r'
self.adapter.critical(msg, self.recording) self.adapter.critical(msg, self.recording)
......
...@@ -132,6 +132,9 @@ Core and Builtins ...@@ -132,6 +132,9 @@ Core and Builtins
Library Library
------- -------
- Issue #20537: logging methods now accept an exception instance as well as a
Boolean value or exception tuple. Thanks to Yury Selivanov for the patch.
- Issue #22384: An exception in Tkinter callback no longer crashes the program - Issue #22384: An exception in Tkinter callback no longer crashes the program
when it is run with pythonw.exe. when it is run with pythonw.exe.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment