Получение локальных переменных вызванной функции перед возвратом в 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
, который не может быть оценен вне атомарной транзакции. Есть ли способ исключить некоторые переменные, когда я регистрирую локальные переменные?