forked from getsentry/sentry-python
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathviews.py
More file actions
127 lines (103 loc) · 4.46 KB
/
Copy pathviews.py
File metadata and controls
127 lines (103 loc) · 4.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import functools
from typing import TYPE_CHECKING
import sentry_sdk
from sentry_sdk.consts import OP
from sentry_sdk.traces import StreamedSpan
from sentry_sdk.tracing_utils import has_span_streaming_enabled
if TYPE_CHECKING:
from typing import Any
try:
from asyncio import iscoroutinefunction
except ImportError:
iscoroutinefunction = None # type: ignore
try:
from sentry_sdk.integrations.django.asgi import wrap_async_view
except (ImportError, SyntaxError):
wrap_async_view = None # type: ignore
def patch_views() -> None:
from django.core.handlers.base import BaseHandler
from django.template.response import SimpleTemplateResponse
from sentry_sdk.integrations.django import DjangoIntegration
old_make_view_atomic = BaseHandler.make_view_atomic
old_render = SimpleTemplateResponse.render
def sentry_patched_render(self: "SimpleTemplateResponse") -> "Any":
span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options)
if span_streaming:
with sentry_sdk.traces.start_span(
name="serialize response",
attributes={
"sentry.op": OP.VIEW_RESPONSE_RENDER,
"sentry.origin": DjangoIntegration.origin,
},
):
return old_render(self)
else:
with sentry_sdk.start_span(
op=OP.VIEW_RESPONSE_RENDER,
name="serialize response",
origin=DjangoIntegration.origin,
):
return old_render(self)
@functools.wraps(old_make_view_atomic)
def sentry_patched_make_view_atomic(
self: "Any", *args: "Any", **kwargs: "Any"
) -> "Any":
callback = old_make_view_atomic(self, *args, **kwargs)
# XXX: The wrapper function is created for every request. Find more
# efficient way to wrap views (or build a cache?)
integration = sentry_sdk.get_client().get_integration(DjangoIntegration)
if integration is not None:
is_async_view = (
iscoroutinefunction is not None
and wrap_async_view is not None
and iscoroutinefunction(callback)
)
if is_async_view:
sentry_wrapped_callback = wrap_async_view(callback)
else:
sentry_wrapped_callback = _wrap_sync_view(callback)
else:
sentry_wrapped_callback = callback
return sentry_wrapped_callback
SimpleTemplateResponse.render = sentry_patched_render
BaseHandler.make_view_atomic = sentry_patched_make_view_atomic
def _wrap_sync_view(callback: "Any") -> "Any":
from sentry_sdk.integrations.django import DjangoIntegration
@functools.wraps(callback)
def sentry_wrapped_callback(request: "Any", *args: "Any", **kwargs: "Any") -> "Any":
client = sentry_sdk.get_client()
span_streaming = has_span_streaming_enabled(client.options)
current_scope = sentry_sdk.get_current_scope()
if span_streaming:
current_span = current_scope.streamed_span
if type(current_span) is StreamedSpan:
segment = current_span._segment
segment._update_active_thread()
else:
if current_scope.transaction is not None:
current_scope.transaction.update_active_thread()
sentry_scope = sentry_sdk.get_isolation_scope()
# set the active thread id to the handler thread for sync views
# this isn't necessary for async views since that runs on main
if sentry_scope.profile is not None:
sentry_scope.profile.update_active_thread_id()
integration = client.get_integration(DjangoIntegration)
if not integration or not integration.middleware_spans:
return callback(request, *args, **kwargs)
if span_streaming:
with sentry_sdk.traces.start_span(
name=request.resolver_match.view_name,
attributes={
"sentry.op": OP.VIEW_RENDER,
"sentry.origin": DjangoIntegration.origin,
},
):
return callback(request, *args, **kwargs)
else:
with sentry_sdk.start_span(
op=OP.VIEW_RENDER,
name=request.resolver_match.view_name,
origin=DjangoIntegration.origin,
):
return callback(request, *args, **kwargs)
return sentry_wrapped_callback