json_splitter: Don't break when buffer contains leading whitespace.

Add error logging with detailed output for decode errors

Signed-off-by: Joffrey F <joffrey@docker.com>
This commit is contained in:
Joffrey F 2016-07-29 14:05:59 -07:00
parent dec2c83014
commit 6f4be1cffc
2 changed files with 28 additions and 1 deletions

View File

@ -5,11 +5,13 @@ import codecs
import hashlib import hashlib
import json import json
import json.decoder import json.decoder
import logging
import six import six
json_decoder = json.JSONDecoder() json_decoder = json.JSONDecoder()
log = logging.getLogger(__name__)
def get_output_stream(stream): def get_output_stream(stream):
@ -60,13 +62,21 @@ def split_buffer(stream, splitter=None, decoder=lambda a: a):
yield item yield item
if buffered: if buffered:
try:
yield decoder(buffered) yield decoder(buffered)
except ValueError:
log.error(
'Compose tried parsing the following chunk as a JSON object, '
'but failed:\n%s' % repr(buffered)
)
raise
def json_splitter(buffer): def json_splitter(buffer):
"""Attempt to parse a json object from a buffer. If there is at least one """Attempt to parse a json object from a buffer. If there is at least one
object, return it and the rest of the buffer, otherwise return None. object, return it and the rest of the buffer, otherwise return None.
""" """
buffer = buffer.strip()
try: try:
obj, index = json_decoder.raw_decode(buffer) obj, index = json_decoder.raw_decode(buffer)
rest = buffer[json.decoder.WHITESPACE.match(buffer, index).end():] rest = buffer[json.decoder.WHITESPACE.match(buffer, index).end():]

View File

@ -15,6 +15,10 @@ class TestJsonSplitter(object):
data = '{"foo": "bar"}\n \n{"next": "obj"}' data = '{"foo": "bar"}\n \n{"next": "obj"}'
assert utils.json_splitter(data) == ({'foo': 'bar'}, '{"next": "obj"}') assert utils.json_splitter(data) == ({'foo': 'bar'}, '{"next": "obj"}')
def test_json_splitter_leading_whitespace(self):
data = '\n \r{"foo": "bar"}\n\n {"next": "obj"}'
assert utils.json_splitter(data) == ({'foo': 'bar'}, '{"next": "obj"}')
class TestStreamAsText(object): class TestStreamAsText(object):
@ -43,3 +47,16 @@ class TestJsonStream(object):
[1, 2, 3], [1, 2, 3],
[], [],
] ]
def test_with_leading_whitespace(self):
stream = [
'\n \r\n {"one": "two"}{"x": 1}',
' {"three": "four"}\t\t{"x": 2}'
]
output = list(utils.json_stream(stream))
assert output == [
{'one': 'two'},
{'x': 1},
{'three': 'four'},
{'x': 2}
]