Получение локальных переменных вызванной функции перед возвратом в python

Я использую Django 2.2, и у меня есть следующее представление (сокращенная версия):

@method_decorator(log_request(settings.LOGGER_PAYMENT_TRANSACTION), "post")
class UltimateOrderPaymentView(SettingsIncludeMixin, APIView, PayTRMixin):
    def post(self, request, *args, **kwargs):
        serializer = UltimatePayOrderSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        orders = Order.objects.filter(
            id__in=serializer.validated_data["order_ids"],
            is_paid=False,
            status_id=Status.objects.order_statuses(level="base").first().id,
            user=request.user,
        ).select_for_update()

        with transaction.atomic():
            ids = list(orders.values_list("id", flat=True))
            if not ids:
                return Response("Orders not found", status=status.HTTP_404_NOT_FOUND)

            return self.__create_transaction_and_generate_url(serializer.validated_data["payment_method"])

И моя логика журнала:

def _log_request_response(view_method, logger):
    @functools.wraps(view_method)
    def wrapper(request, *args, **kwargs):
        log = logging.getLogger(logger)

        response = view_method(request, *args, **kwargs)

        if isinstance(response, Response):
            data = response.data
        elif isinstance(response, JsonResponse):
            data = response.content.decode()
        else:
            data = f"Unprocessable type: {type(response)}"

        log.info(f"URL: {request.path}. Data: {request.data}. Response: {data}")
        return response

    return wrapper


def log_request(name="django.request"):
    return functools.partial(_log_request_response, logger=name)

Все работает отлично, уже прошло несколько месяцев с тех пор, как этот код работает в продакшене, и я могу видеть как данные запроса, так и данные ответа. Однако теперь я хотел бы получить список локальных переменных (и их значений), зарегистрированной функции (view_method). Больше похоже на Sentry, когда он показывает список локальных переменных, когда происходит исключение (но в данном случае исключения нет).

TRY 1: Я пробовал inspect.stack(), но поскольку функция вызывается и завершается, она перестает существовать в стеке вызовов. Таким образом, inspect.stack() возвращает только предыдущие функции, до обертки.

TRY 2: Я пробовал использовать sys.settrace(), но так как в view_method также есть несколько вызовов функций, я не смог отследить только post функцию данного представления. Мой фрагмент кода:

def trace_local_vars(frame, event, arg):
    if event == "return":
        if (
            "virtualenvs" not in frame.f_code.co_filename
            and "python3.7" not in frame.f_code.co_filename
            and "<" not in frame.f_code.co_filename
        ):
            print(frame.f_code.co_filename, frame.f_locals)
            return frame.f_locals

    return trace_local_vars

И моя обертка журнала:

def _log_request_response(view_method: functools.partial, logger):
    @functools.wraps(view_method)
    def wrapper(request, *args, **kwargs):
        log = logging.getLogger(logger)

        sys.settrace(trace_local_vars)
        response = view_method(request, *args, **kwargs)
        sys.settrace(None)

        if isinstance(response, Response):
            data = response.data
        elif isinstance(response, JsonResponse):
            data = response.content.decode()
        else:
            data = f"Unprocessable type: {type(response)}"

        log.info(f"URL: {request.path}. Data: {request.data}. Response: {data}")
        return response

    return wrapper

TRY 3: Пробовал использовать объект trace, но этот объект не поддерживает чтение локальных переменных из вызываемой функции.

ПРОБЛЕМА 1

Я не могу изменить метод post представления. Более того, я хочу, чтобы этот лог был универсальным, который может украсить любой APIView и его относительную функцию

ПРОБЛЕМА 2

При использовании sys.settrace() я смог вывести (не получить!) список локальных переменных функции post (и многих других, не смог их разделить). Я получил следующий вывод

Ошибка происходит, потому что, когда трассировщик пытается получить доступ к переменной orders функции post, он выдает ошибку, потому что этот набор запросов использует select_for_update, который не может быть оценен вне атомарной транзакции. Есть ли способ исключить некоторые переменные, когда я регистрирую локальные переменные?

Вернуться на верх