Предельное количество предметов / длина json для регистрации - PullRequest
0 голосов
/ 19 февраля 2020

Я работаю над API, который возвращает JSON. Я записываю свои ответы, и иногда JSON просто абсурдно длинен и в основном забивает мои лог-файлы. Есть ли аккуратный способ уменьшить длину JSON, исключительно для визуальной регистрации данных? (не действует в производстве)

Основной подход c заключается в сокращении массивов на длину от 5 до [первые 2, "...", последние 2] и словари с более чем 4 пунктами в {первые 4, "...": "..."}

Код ниже уродлив. Я знаю, что это должно быть рекурсивное решение, которое сокращает элементы таким же образом для JSON произвольной глубины - в настоящее время оно делает это только для глубины 2.

def log_reducer(response_log):
original_response_log = response_log
try:
    if type(response_log) == dict:
        if len(response_log) >= 4:  # {123456}
            response_log = dict(list(response_log.items())[:4])
            response_log.update({"...": "..."})  # {1234...}
        for key, value in response_log.items():
            if type(value) == list:
                if len(value) >= 5:  # {key:[123456]}
                    new_item = value[:2] + ['...'] + value[-2:]  # {[12...56]}
                    response_log.update({key: new_item})
            if type(value) == dict:
                if len(value) >= 4:  # {key:{123456}}
                    reduced_dict = dict(list(value.items())[:4])
                    reduced_dict.update({"...": "..."})
                    response_log.update({key: reduced_dict})  # {{1234...}}

    elif type(response_log) == list:
        if len(response_log) >= 5:  # [123456]
            response_log = response_log[:2] + ['...'] + response_log[-2:]  # [12...56]
        for inner_item in response_log:
            if type(inner_item) == list:
                if len(inner_item) >= 5:  # [[123456]]
                    reduced_list = inner_item[:2] + ['...'] + inner_item[-2:]  # [[12...56]]
                    response_log.remove(inner_item)
                    response_log.append(reduced_list)
            if type(inner_item) == dict:
                if len(inner_item) >= 4:  # [{123456}]
                    reduced_dict = dict(list(inner_item.items())[:4])
                    reduced_dict.update({"...": "..."})  # [{1234...}]
                    response_log.remove(inner_item)
                    response_log.append(reduced_dict)
except Exception as e:
    return original_response_log
return response_log

Возвращенный response_log тогда зарегистрировано с помощью logger.info (str (response_log))

Как видите, тот факт, что на каждом уровне могут быть либо массивы, либо словари, делает эту задачу немного более сложной, и я изо всех сил пытаюсь найти библиотека или код любого рода, который бы упростил это. Если кто-то захочет дать ему шанс, я был бы очень признателен.

Вы можете использовать тест JSON, подобный этому, чтобы увидеть его в действии:

test_json = {"works": [1, 2, 3, 4, 5, 6],
             "not_affected": [{"1": "1", "2": "2", "3": "3", "4": "4", "5": "5"}],
             "1": "1", "2": "2", "3": "3",
             "removed": "removed"
             }
print("original", test_json)
reduced_log = log_reducer(test_json)
print("reduced", reduced_log)

print("original", test_json)
reduced_log = log_reducer([test_json])  # <- increases nesting depth
print("reduced", reduced_log)

Ответы [ 2 ]

1 голос
/ 19 февраля 2020

В этом ответе используется идея @ calceamenta, но реализуются фактические логики сокращения c:

def recursive_reduce(obj):
    if isinstance(obj, (float, str, int, bool, type(None))):
        return obj

    if isinstance(obj, dict):
        keys = list(sorted(obj))
        obj['...'] = '...'

        if len(keys) > 5:
            new_keys = keys[:2] + ["..."] + keys[-2:]
        else:
            new_keys = keys

        new_dict = {x:obj[x] for x in new_keys}
        for k, v in new_dict.items():
            new_dict[k] = recursive_reduce(v)

        return new_dict

    if isinstance(obj, list):
        if len(obj) > 5:
            new_list = obj[:2] + ["..."] + obj[-2:]
        else:
            new_list = obj

        for i, v in enumerate(new_list):
            new_list[i] = recursive_reduce(v)

        return new_list

    return str(obj)

test_json = {"works": [1, 2, 3, 4, 5, 6],
             "not_affected": [{"1": "1", "2": "2", "3": "3", "4": "4", "5": "5"}],
             "1": "1", "2": "2", "3": "3",
             "removed": "removed"
             }

print("original", test_json)
reduced_log = recursive_reduce(test_json)
print("reduced", reduced_log)

Вывод:

original {'works': [1, 2, 3, 4, 5, 6], 'not_affected': [{'1': '1', '2': '2', '3': '3', '4': '4', '5': '5'}], '1': '1', '2': '2', '3': '3', 'removed': 'removed'}
reduced {'1': '1', '2': '2', '...': '...', 'removed': 'removed', 'works': [1, 2, '...', 5, 6]}

Надеюсь, это поможет:)

1 голос
/ 19 февраля 2020

Вы можете перезаписать строковое представление диктов и списков в python, используя метод def __str __ (): . Используя это просто рекурсивно вызовите функцию печати для всех элементов. У него может быть простой шаблон:

def custom_print(obj):
    log_str = ''
    if type(obj) == list:
        for item in obj:
            log_str += custom_print(item)
    elif type(obj) == dict:
        for k, item in obj.items():
            custom_print(item)

Используйте эту пользовательскую функцию журнала для печати в файл журнала в соответствии с форматом файла журнала.

...