|
| 1 | +import json |
| 2 | +from typing import TYPE_CHECKING |
| 3 | + |
1 | 4 | import sentry_sdk |
2 | | -from sentry_sdk.integrations import _check_minimum_version, DidNotEnable, Integration |
| 5 | +from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version |
3 | 6 | from sentry_sdk.integrations._wsgi_common import ( |
| 7 | + _RAW_DATA_EXCEPTIONS, |
4 | 8 | DEFAULT_HTTP_METHODS_TO_CAPTURE, |
5 | 9 | RequestExtractor, |
| 10 | + request_body_within_bounds, |
6 | 11 | ) |
7 | 12 | from sentry_sdk.integrations.wsgi import SentryWsgiMiddleware |
8 | 13 | from sentry_sdk.scope import should_send_default_pii |
| 14 | +from sentry_sdk.traces import StreamedSpan, _get_current_streamed_span |
9 | 15 | from sentry_sdk.tracing import SOURCE_FOR_STYLE |
| 16 | +from sentry_sdk.tracing_utils import has_span_streaming_enabled |
10 | 17 | from sentry_sdk.utils import ( |
| 18 | + AnnotatedValue, |
11 | 19 | capture_internal_exceptions, |
12 | 20 | ensure_integration_enabled, |
13 | 21 | event_from_exception, |
14 | 22 | package_version, |
15 | 23 | ) |
16 | 24 |
|
17 | | -from typing import TYPE_CHECKING |
18 | | - |
19 | 25 | if TYPE_CHECKING: |
20 | 26 | from typing import Any, Callable, Dict, Union |
21 | 27 |
|
| 28 | + from werkzeug.datastructures import FileStorage, ImmutableMultiDict |
| 29 | + |
22 | 30 | from sentry_sdk._types import Event, EventProcessor |
23 | 31 | from sentry_sdk.integrations.wsgi import _ScopedResponse |
24 | | - from werkzeug.datastructures import FileStorage, ImmutableMultiDict |
25 | 32 |
|
26 | 33 |
|
27 | 34 | try: |
@@ -94,10 +101,9 @@ def setup_once() -> None: |
94 | 101 | def sentry_patched_wsgi_app( |
95 | 102 | self: "Any", environ: "Dict[str, str]", start_response: "Callable[..., Any]" |
96 | 103 | ) -> "_ScopedResponse": |
97 | | - if sentry_sdk.get_client().get_integration(FlaskIntegration) is None: |
98 | | - return old_app(self, environ, start_response) |
99 | | - |
100 | 104 | integration = sentry_sdk.get_client().get_integration(FlaskIntegration) |
| 105 | + if integration is None: |
| 106 | + return old_app(self, environ, start_response) |
101 | 107 |
|
102 | 108 | middleware = SentryWsgiMiddleware( |
103 | 109 | lambda *a, **kw: old_app(self, *a, **kw), |
@@ -158,6 +164,49 @@ def _request_started(app: "Flask", **kwargs: "Any") -> None: |
158 | 164 | evt_processor = _make_request_event_processor(app, request, integration) |
159 | 165 | scope.add_event_processor(evt_processor) |
160 | 166 |
|
| 167 | + client = sentry_sdk.get_client() |
| 168 | + if has_span_streaming_enabled(client.options): |
| 169 | + _set_request_body_data_on_streaming_segment(request, client) |
| 170 | + |
| 171 | + |
| 172 | +def _set_request_body_data_on_streaming_segment( |
| 173 | + request: "Request", client: "sentry_sdk.client.BaseClient" |
| 174 | +) -> None: |
| 175 | + current_span = _get_current_streamed_span() |
| 176 | + if type(current_span) is not StreamedSpan: |
| 177 | + return |
| 178 | + |
| 179 | + with capture_internal_exceptions(): |
| 180 | + content_length = int(request.content_length or 0) |
| 181 | + extractor = FlaskRequestExtractor(request) |
| 182 | + |
| 183 | + if not request_body_within_bounds(client, content_length): |
| 184 | + data = AnnotatedValue.substituted_because_over_size_limit() |
| 185 | + else: |
| 186 | + raw_data = None |
| 187 | + try: |
| 188 | + raw_data = extractor.raw_data() |
| 189 | + except _RAW_DATA_EXCEPTIONS: |
| 190 | + pass |
| 191 | + |
| 192 | + parsed_body = extractor.parsed_body() |
| 193 | + if parsed_body is not None: |
| 194 | + data = parsed_body |
| 195 | + elif raw_data: |
| 196 | + data = AnnotatedValue.substituted_because_raw_data() |
| 197 | + else: |
| 198 | + return |
| 199 | + |
| 200 | + def _default(value: "Any") -> "Any": |
| 201 | + if isinstance(value, AnnotatedValue): |
| 202 | + return value.value |
| 203 | + return str(value) |
| 204 | + |
| 205 | + current_span._segment.set_attribute( |
| 206 | + "http.request.body.data", |
| 207 | + json.dumps(data, default=_default), |
| 208 | + ) |
| 209 | + |
161 | 210 |
|
162 | 211 | class FlaskRequestExtractor(RequestExtractor): |
163 | 212 | def env(self) -> "Dict[str, str]": |
|
0 commit comments