Skip to content

Commit

Permalink
Truncate error_summary if exc_info not explicitly passed
Browse files Browse the repository at this point in the history
Currently, when logging at level >= WARNING, exception information is
added to the log message as an "error summary" for operators. The error
summary includes the exception type and the message. However, when the
exception is a _Remote exception generated from oslo.messaging and sent
over RPC, the full traceback from the exception is appended to the
exception message [1] to preserve it. So, the error summary ends up
outputting the full traceback, unintentionally.

This truncates the error_summary to keep only the first line unless
exc_info was explicitly passed, via LOG.exception(), for example.

Closes-Bug: #1729475

[1] https://github.com/openstack/oslo.messaging/blob/8d42484/oslo_messaging/_drivers/common.py#L208

Change-Id: I2e4e356d23dff2e6ac1946fe9e994c4d962ab55a
  • Loading branch information
melwitt committed Jan 3, 2018
1 parent 97434d4 commit a63438c
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 0 deletions.
7 changes: 7 additions & 0 deletions oslo_log/formatters.py
Expand Up @@ -156,6 +156,13 @@ def _get_error_summary(record):
exc_info[0],
exc_info[1],
)[0].rstrip()
# If the exc_info wasn't explicitly passed to us, take only the
# first line of it. _Remote exceptions from oslo.messaging append
# the full traceback to the exception message, so we want to avoid
# outputting the traceback unless we've been passed exc_info
# directly (via LOG.exception(), for example).
if not record.exc_info:
error_summary = error_summary.split('\n', 1)[0]
except TypeError as type_err:
# Work around https://bugs.python.org/issue28603
error_summary = "<exception with %s>" % six.text_type(type_err)
Expand Down
24 changes: 24 additions & 0 deletions oslo_log/tests/unit/test_log.py
Expand Up @@ -541,6 +541,30 @@ def test_no_exception(self):
self.assertIn('error_summary', data)
self.assertEqual('', data['error_summary'])

def test_exception_without_exc_info_passed(self):
ctxt = _fake_context()
ctxt.request_id = six.text_type('99')
try:
raise RuntimeError('test_exception\ntraceback\nfrom\nremote error')
except RuntimeError:
self.log.warning('testing', context=ctxt)
data = jsonutils.loads(self.stream.getvalue())
self.assertIn('error_summary', data)
self.assertEqual('RuntimeError: test_exception', data['error_summary'])

def test_exception_with_exc_info_passed(self):
ctxt = _fake_context()
ctxt.request_id = six.text_type('99')
try:
raise RuntimeError('test_exception\ntraceback\nfrom\nremote error')
except RuntimeError:
self.log.exception('testing', context=ctxt)
data = jsonutils.loads(self.stream.getvalue())
self.assertIn('error_summary', data)
self.assertEqual('RuntimeError: test_exception'
'\ntraceback\nfrom\nremote error',
data['error_summary'])

def test_fallback(self):
if not formatters._HAVE_JSONUTILS_FALLBACK:
self.skipTest("need the fallback parameter of "
Expand Down

0 comments on commit a63438c

Please sign in to comment.