Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 660
feat(httpx): Migrate to span first#6084
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
b47362d019fa476815bc6bf3969025a953e9d2546f19eeac5a632a81a394e2f4ec4ce6File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,12 @@ | ||
| import sentry_sdk | ||
| from sentry_sdk import start_span | ||
| from sentry_sdk.consts import OP, SPANDATA | ||
| from sentry_sdk.integrations import Integration, DidNotEnable | ||
| from sentry_sdk.tracing import BAGGAGE_HEADER_NAME | ||
| from sentry_sdk.tracing_utils import ( | ||
| should_propagate_trace, | ||
| add_http_request_source, | ||
| should_propagate_trace, | ||
| add_sentry_baggage_to_headers, | ||
| has_span_streaming_enabled, | ||
| ) | ||
| from sentry_sdk.utils import ( | ||
| SENSITIVE_DATA_SUBSTITUTE, | ||
| @@ -20,6 +20,7 @@ | ||
| if TYPE_CHECKING: | ||
| from typing import Any | ||
| from sentry_sdk._types import Attributes | ||
| try: | ||
| @@ -49,48 +50,102 @@ def _install_httpx_client() -> None: | ||
| @ensure_integration_enabled(HttpxIntegration, real_send) | ||
| def send(self: "Client", request: "Request", **kwargs: "Any") -> "Response": | ||
| client = sentry_sdk.get_client() | ||
| is_span_streaming_enabled = has_span_streaming_enabled(client.options) | ||
| parsed_url = None | ||
| with capture_internal_exceptions(): | ||
| parsed_url = parse_url(str(request.url), sanitize=False) | ||
| with start_span( | ||
| op=OP.HTTP_CLIENT, | ||
| name="%s %s" | ||
| % ( | ||
| request.method, | ||
| parsed_url.url if parsed_url else SENSITIVE_DATA_SUBSTITUTE, | ||
| ), | ||
| origin=HttpxIntegration.origin, | ||
| ) as span: | ||
| span.set_data(SPANDATA.HTTP_METHOD, request.method) | ||
| if parsed_url is not None: | ||
| span.set_data("url", parsed_url.url) | ||
| span.set_data(SPANDATA.HTTP_QUERY, parsed_url.query) | ||
| span.set_data(SPANDATA.HTTP_FRAGMENT, parsed_url.fragment) | ||
| if should_propagate_trace(sentry_sdk.get_client(), str(request.url)): | ||
| for ( | ||
| key, | ||
| value, | ||
| ) in sentry_sdk.get_current_scope().iter_trace_propagation_headers(): | ||
| logger.debug( | ||
| "[Tracing] Adding `{key}` header {value} to outgoing request to {url}.".format( | ||
| key=key, value=value, url=request.url | ||
| if is_span_streaming_enabled: | ||
| with sentry_sdk.traces.start_span( | ||
| name="%s %s" | ||
| % ( | ||
| request.method, | ||
| parsed_url.url if parsed_url else SENSITIVE_DATA_SUBSTITUTE, | ||
| ), | ||
| attributes={ | ||
| "sentry.op": OP.HTTP_CLIENT, | ||
| "sentry.origin": HttpxIntegration.origin, | ||
| "http.request.method": request.method, | ||
| }, | ||
| ) as streamed_span: | ||
| attributes: "Attributes" = {} | ||
| if parsed_url is not None: | ||
| attributes["url.full"] = parsed_url.url | ||
| if parsed_url.query: | ||
| attributes["url.query"] = parsed_url.query | ||
| if parsed_url.fragment: | ||
| attributes["url.fragment"] = parsed_url.fragment | ||
| if should_propagate_trace(client, str(request.url)): | ||
| for ( | ||
| key, | ||
| value, | ||
| ) in ( | ||
| sentry_sdk.get_current_scope().iter_trace_propagation_headers() | ||
| ): | ||
| logger.debug( | ||
| f"[Tracing] Adding `{key}` header {value} to outgoing request to {request.url}." | ||
| ) | ||
| ) | ||
| if key == BAGGAGE_HEADER_NAME: | ||
| add_sentry_baggage_to_headers(request.headers, value) | ||
| else: | ||
| request.headers[key] = value | ||
| if key == BAGGAGE_HEADER_NAME: | ||
| add_sentry_baggage_to_headers(request.headers, value) | ||
| else: | ||
| request.headers[key] = value | ||
| rv = real_send(self, request, **kwargs) | ||
| try: | ||
| rv = real_send(self, request, **kwargs) | ||
| span.set_http_status(rv.status_code) | ||
| span.set_data("reason", rv.reason_phrase) | ||
| streamed_span.status = "error" if rv.status_code >= 400 else "ok" | ||
| attributes["http.response.status_code"] = rv.status_code | ||
| finally: | ||
| streamed_span.set_attributes(attributes) | ||
| with capture_internal_exceptions(): | ||
| add_http_request_source(span) | ||
| # Needs to happen within the context manager as we want to attach the | ||
| # final data before the span finishes and is sent for ingesting. | ||
| with capture_internal_exceptions(): | ||
| add_http_request_source(streamed_span) | ||
cursor[bot] marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| else: | ||
| with sentry_sdk.start_span( | ||
| op=OP.HTTP_CLIENT, | ||
| name="%s %s" | ||
| % ( | ||
| request.method, | ||
| parsed_url.url if parsed_url else SENSITIVE_DATA_SUBSTITUTE, | ||
| ), | ||
| origin=HttpxIntegration.origin, | ||
| ) as span: | ||
| span.set_data(SPANDATA.HTTP_METHOD, request.method) | ||
| if parsed_url is not None: | ||
| span.set_data("url", parsed_url.url) | ||
| span.set_data(SPANDATA.HTTP_QUERY, parsed_url.query) | ||
| span.set_data(SPANDATA.HTTP_FRAGMENT, parsed_url.fragment) | ||
| if should_propagate_trace(client, str(request.url)): | ||
| for ( | ||
| key, | ||
| value, | ||
| ) in ( | ||
| sentry_sdk.get_current_scope().iter_trace_propagation_headers() | ||
| ): | ||
| logger.debug( | ||
| f"[Tracing] Adding `{key}` header {value} to outgoing request to {request.url}." | ||
| ) | ||
| if key == BAGGAGE_HEADER_NAME: | ||
| add_sentry_baggage_to_headers(request.headers, value) | ||
| else: | ||
| request.headers[key] = value | ||
| rv = real_send(self, request, **kwargs) | ||
| span.set_http_status(rv.status_code) | ||
| span.set_data("reason", rv.reason_phrase) | ||
| with capture_internal_exceptions(): | ||
| add_http_request_source(span) | ||
| return rv | ||
| @@ -103,50 +158,103 @@ def _install_httpx_async_client() -> None: | ||
| async def send( | ||
| self: "AsyncClient", request: "Request", **kwargs: "Any" | ||
| ) -> "Response": | ||
| if sentry_sdk.get_client().get_integration(HttpxIntegration) is None: | ||
| client = sentry_sdk.get_client() | ||
| if client.get_integration(HttpxIntegration) is None: | ||
| return await real_send(self, request, **kwargs) | ||
| is_span_streaming_enabled = has_span_streaming_enabled(client.options) | ||
| parsed_url = None | ||
| with capture_internal_exceptions(): | ||
| parsed_url = parse_url(str(request.url), sanitize=False) | ||
| with start_span( | ||
| op=OP.HTTP_CLIENT, | ||
| name="%s %s" | ||
| % ( | ||
| request.method, | ||
| parsed_url.url if parsed_url else SENSITIVE_DATA_SUBSTITUTE, | ||
| ), | ||
| origin=HttpxIntegration.origin, | ||
| ) as span: | ||
| span.set_data(SPANDATA.HTTP_METHOD, request.method) | ||
| if parsed_url is not None: | ||
| span.set_data("url", parsed_url.url) | ||
| span.set_data(SPANDATA.HTTP_QUERY, parsed_url.query) | ||
| span.set_data(SPANDATA.HTTP_FRAGMENT, parsed_url.fragment) | ||
| if should_propagate_trace(sentry_sdk.get_client(), str(request.url)): | ||
| for ( | ||
| key, | ||
| value, | ||
| ) in sentry_sdk.get_current_scope().iter_trace_propagation_headers(): | ||
| logger.debug( | ||
| "[Tracing] Adding `{key}` header {value} to outgoing request to {url}.".format( | ||
| key=key, value=value, url=request.url | ||
| if is_span_streaming_enabled: | ||
| with sentry_sdk.traces.start_span( | ||
| name="%s %s" | ||
| % ( | ||
| request.method, | ||
| parsed_url.url if parsed_url else SENSITIVE_DATA_SUBSTITUTE, | ||
| ), | ||
| attributes={ | ||
| "sentry.op": OP.HTTP_CLIENT, | ||
| "sentry.origin": HttpxIntegration.origin, | ||
| "http.request.method": request.method, | ||
| }, | ||
| ) as streamed_span: | ||
| attributes: "Attributes" = {} | ||
| if parsed_url is not None: | ||
| attributes["url.full"] = parsed_url.url | ||
| if parsed_url.query: | ||
| attributes["url.query"] = parsed_url.query | ||
| if parsed_url.fragment: | ||
| attributes["url.fragment"] = parsed_url.fragment | ||
| if should_propagate_trace(client, str(request.url)): | ||
| for ( | ||
| key, | ||
| value, | ||
| ) in ( | ||
| sentry_sdk.get_current_scope().iter_trace_propagation_headers() | ||
| ): | ||
| logger.debug( | ||
| f"[Tracing] Adding `{key}` header {value} to outgoing request to {request.url}." | ||
| ) | ||
| ) | ||
| if key == BAGGAGE_HEADER_NAME: | ||
| add_sentry_baggage_to_headers(request.headers, value) | ||
| else: | ||
| request.headers[key] = value | ||
| rv = await real_send(self, request, **kwargs) | ||
| if key == BAGGAGE_HEADER_NAME: | ||
| add_sentry_baggage_to_headers(request.headers, value) | ||
| else: | ||
| request.headers[key] = value | ||
| span.set_http_status(rv.status_code) | ||
| span.set_data("reason", rv.reason_phrase) | ||
| try: | ||
| rv = await real_send(self, request, **kwargs) | ||
| with capture_internal_exceptions(): | ||
| add_http_request_source(span) | ||
| streamed_span.status = "error" if rv.status_code >= 400 else "ok" | ||
| attributes["http.response.status_code"] = rv.status_code | ||
| finally: | ||
| streamed_span.set_attributes(attributes) | ||
| # Needs to happen within the context manager as we want to attach the | ||
| # final data before the span finishes and is sent for ingesting. | ||
| with capture_internal_exceptions(): | ||
| add_http_request_source(streamed_span) | ||
| else: | ||
| with sentry_sdk.start_span( | ||
| op=OP.HTTP_CLIENT, | ||
| name="%s %s" | ||
| % ( | ||
| request.method, | ||
| parsed_url.url if parsed_url else SENSITIVE_DATA_SUBSTITUTE, | ||
| ), | ||
| origin=HttpxIntegration.origin, | ||
| ) as span: | ||
| span.set_data(SPANDATA.HTTP_METHOD, request.method) | ||
| if parsed_url is not None: | ||
| span.set_data("url", parsed_url.url) | ||
| span.set_data(SPANDATA.HTTP_QUERY, parsed_url.query) | ||
| span.set_data(SPANDATA.HTTP_FRAGMENT, parsed_url.fragment) | ||
| if should_propagate_trace(client, str(request.url)): | ||
| for ( | ||
| key, | ||
| value, | ||
| ) in ( | ||
| sentry_sdk.get_current_scope().iter_trace_propagation_headers() | ||
| ): | ||
| logger.debug( | ||
| f"[Tracing] Adding `{key}` header {value} to outgoing request to {request.url}." | ||
| ) | ||
| if key == BAGGAGE_HEADER_NAME: | ||
| add_sentry_baggage_to_headers(request.headers, value) | ||
| else: | ||
| request.headers[key] = value | ||
| rv = await real_send(self, request, **kwargs) | ||
| span.set_http_status(rv.status_code) | ||
| span.set_data("reason", rv.reason_phrase) | ||
| with capture_internal_exceptions(): | ||
| add_http_request_source(span) | ||
| return rv | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -278,12 +278,9 @@ def __init__( | ||
| self._start_timestamp = datetime.now(timezone.utc) | ||
| self._timestamp: "Optional[datetime]" = None | ||
| try: | ||
| # profiling depends on this value and requires that | ||
| # it is measured in nanoseconds | ||
| self._start_timestamp_monotonic_ns = nanosecond_time() | ||
| except AttributeError: | ||
| pass | ||
| # profiling depends on this value and requires that | ||
| # it is measured in nanoseconds | ||
| self._start_timestamp_monotonic_ns = nanosecond_time() | ||
ericapisani marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| self._span_id: "Optional[str]" = None | ||
| @@ -385,13 +382,10 @@ def _end(self, end_timestamp: "Optional[Union[float, datetime]]" = None) -> None | ||
| ) | ||
| if self._timestamp is None: | ||
| try: | ||
| elapsed = nanosecond_time() - self._start_timestamp_monotonic_ns | ||
| self._timestamp = self._start_timestamp + timedelta( | ||
| microseconds=elapsed / 1000 | ||
| ) | ||
| except AttributeError: | ||
| self._timestamp = datetime.now(timezone.utc) | ||
| elapsed = nanosecond_time() - self._start_timestamp_monotonic_ns | ||
| self._timestamp = self._start_timestamp + timedelta( | ||
| microseconds=elapsed / 1000 | ||
| ) | ||
| client = sentry_sdk.get_client() | ||
| if not client.is_active(): | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please see my comments on the async send since this is essentially the same changeset