Skip to content

Commit c7a80ae

Browse files
authored
fix: Another attempt at getting DRF body data (getsentry#393)
1 parent 2796e76 commit c7a80ae

File tree

4 files changed

+50
-9
lines changed

4 files changed

+50
-9
lines changed

sentry_sdk/integrations/django/__init__.py

+26
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,25 @@ def sentry_patched_get_response(self, request):
124124

125125
BaseHandler.get_response = sentry_patched_get_response
126126

127+
try:
128+
from rest_framework.views import APIView # type: ignore
129+
except ImportError:
130+
pass
131+
else:
132+
# DRF's request type (which wraps the Django request and proxies
133+
# all attrs) has some attributes such as `data` which buffer
134+
# request data. We want to use those in the RequestExtractor to
135+
# get body data more reliably.
136+
old_drf_initial = APIView.initial
137+
138+
def sentry_patched_drf_initial(self, request, *args, **kwargs):
139+
with capture_internal_exceptions():
140+
request._request._sentry_drf_request_backref = weakref.ref(request)
141+
pass
142+
return old_drf_initial(self, request, *args, **kwargs)
143+
144+
APIView.initial = sentry_patched_drf_initial
145+
127146
signals.got_request_exception.connect(_got_request_exception)
128147

129148
@add_global_event_processor
@@ -197,6 +216,13 @@ def event_processor(event, hint):
197216
if request is None:
198217
return event
199218

219+
try:
220+
drf_request = request._sentry_drf_request_backref()
221+
if drf_request is not None:
222+
request = drf_request
223+
except AttributeError:
224+
pass
225+
200226
try:
201227
if integration.transaction_style == "function_name":
202228
event["transaction"] = transaction_from_function(

tests/integrations/django/myapp/urls.py

+7
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@
4242
urlpatterns.append(
4343
path("rest-framework-exc", views.rest_framework_exc, name="rest_framework_exc")
4444
)
45+
urlpatterns.append(
46+
path(
47+
"rest-framework-read-body-and-exc",
48+
views.rest_framework_read_body_and_exc,
49+
name="rest_framework_read_body_and_exc",
50+
)
51+
)
4552
except AttributeError:
4653
pass
4754

tests/integrations/django/myapp/views.py

+5
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@
1111
def rest_framework_exc(request):
1212
1 / 0
1313

14+
@api_view(["POST"])
15+
def rest_framework_read_body_and_exc(request):
16+
request.data
17+
1 / 0
18+
1419

1520
except ImportError:
1621
pass

tests/integrations/django/test_basic.py

+12-9
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ def test_read_request(sentry_init, client, capture_events):
374374

375375
event, = events
376376

377-
assert event["request"]["data"] == {"hey": 42}
377+
assert "data" not in event["request"]
378378

379379

380380
def test_template_exception(sentry_init, client, capture_events):
@@ -413,12 +413,15 @@ def test_template_exception(sentry_init, client, capture_events):
413413
]
414414

415415

416+
@pytest.mark.parametrize(
417+
"route", ["rest_framework_exc", "rest_framework_read_body_and_exc"]
418+
)
416419
@pytest.mark.parametrize(
417420
"type,event_request",
418421
[
419422
[
420423
"json",
421-
{
424+
lambda route: {
422425
"cookies": {},
423426
"data": {"foo": "bar"},
424427
"env": {"SERVER_NAME": "localhost", "SERVER_PORT": "80"},
@@ -429,12 +432,12 @@ def test_template_exception(sentry_init, client, capture_events):
429432
},
430433
"method": "POST",
431434
"query_string": "",
432-
"url": "http://localhost/rest-framework-exc",
435+
"url": "http://localhost/{}".format(route.replace("_", "-")),
433436
},
434437
],
435438
[
436439
"formdata",
437-
{
440+
lambda route: {
438441
"cookies": {},
439442
"data": {"foo": "bar"},
440443
"env": {"SERVER_NAME": "localhost", "SERVER_PORT": "80"},
@@ -445,13 +448,13 @@ def test_template_exception(sentry_init, client, capture_events):
445448
},
446449
"method": "POST",
447450
"query_string": "",
448-
"url": "http://localhost/rest-framework-exc",
451+
"url": "http://localhost/{}".format(route.replace("_", "-")),
449452
},
450453
],
451454
],
452455
)
453456
def test_rest_framework_basic(
454-
sentry_init, client, capture_events, capture_exceptions, type, event_request
457+
sentry_init, client, capture_events, capture_exceptions, type, event_request, route
455458
):
456459
pytest.importorskip("rest_framework")
457460
sentry_init(integrations=[DjangoIntegration()], send_default_pii=True)
@@ -460,12 +463,12 @@ def test_rest_framework_basic(
460463

461464
if type == "json":
462465
client.post(
463-
reverse("rest_framework_exc"),
466+
reverse(route),
464467
data=json.dumps({"foo": "bar"}),
465468
content_type="application/json",
466469
)
467470
elif type == "formdata":
468-
client.post(reverse("rest_framework_exc"), data={"foo": "bar"})
471+
client.post(reverse(route), data={"foo": "bar"})
469472
else:
470473
assert False
471474

@@ -475,4 +478,4 @@ def test_rest_framework_basic(
475478
event, = events
476479
assert event["exception"]["values"][0]["mechanism"]["type"] == "django"
477480

478-
assert event["request"] == event_request
481+
assert event["request"] == event_request(route)

0 commit comments

Comments
 (0)