Merge "JSONFormatter convert unserializable with repr()"

This commit is contained in:
Zuul 2017-11-30 11:16:27 +00:00 committed by Gerrit Code Review
commit a96f9fa772
3 changed files with 48 additions and 1 deletions

View File

@ -12,6 +12,7 @@
import datetime
import debtcollector
import functools
import itertools
import logging
import logging.config
@ -32,6 +33,15 @@ if six.PY3:
from functools import reduce
try:
# Test if to_primitive() has the fallback parameter added
# in oslo.serialization 2.21.1
jsonutils.to_primitive(1, fallback=repr)
_HAVE_JSONUTILS_FALLBACK = True
except TypeError:
_HAVE_JSONUTILS_FALLBACK = False
def _dictify_context(context):
if getattr(context, 'get_logging_values', None):
return context.get_logging_values()
@ -238,7 +248,16 @@ class JSONFormatter(logging.Formatter):
if record.exc_info:
message['traceback'] = self.formatException(record.exc_info)
return jsonutils.dumps(message)
if _HAVE_JSONUTILS_FALLBACK:
# Bug #1593641: If an object cannot be serialized to JSON, convert
# it using repr() to prevent serialization errors. Using repr() is
# not ideal, but serialization errors are unexpected on logs,
# especially when the code using logs is not aware that the
# JSONFormatter will be used.
convert = functools.partial(jsonutils.to_primitive, fallback=repr)
return jsonutils.dumps(message, default=convert)
else:
return jsonutils.dumps(message)
class FluentFormatter(logging.Formatter):

View File

@ -541,6 +541,28 @@ class JSONFormatterTestCase(LogTestBase):
self.assertIn('error_summary', data)
self.assertEqual('', data['error_summary'])
def test_fallback(self):
if not formatters._HAVE_JSONUTILS_FALLBACK:
self.skipTest("need the fallback parameter of "
"jsonutils.to_primitive() added in "
"oslo_serialization 2.21.1")
class MyObject(object):
def __str__(self):
return 'str'
def __repr__(self):
return 'repr'
obj = MyObject()
self.log.debug('obj=%s', obj)
data = jsonutils.loads(self.stream.getvalue())
self.assertEqual('obj=str', data['message'])
# Bug #1593641: If an object of record.args cannot be serialized,
# convert it using repr() to prevent serialization error on logging.
self.assertEqual(['repr'], data['args'])
def get_fake_datetime(retval):
class FakeDateTime(datetime.datetime):

View File

@ -0,0 +1,6 @@
---
fixes:
- |
The JSONFormatter formatter now converts unserializable objects with
repr() to prevent JSON serialization errors on logging. The fix requires
oslo.serialization 2.21.1 or newer. (Bug #1593641)