-
Notifications
You must be signed in to change notification settings - Fork 462
/
httpx.py
112 lines (84 loc) · 3.7 KB
/
httpx.py
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
from sentry_sdk import Hub
from sentry_sdk.consts import OP, SPANDATA
from sentry_sdk.integrations import Integration, DidNotEnable
from sentry_sdk.tracing_utils import should_propagate_trace
from sentry_sdk.utils import logger, parse_url
from sentry_sdk._types import TYPE_CHECKING
if TYPE_CHECKING:
from typing import Any
try:
from httpx import AsyncClient, Client, Request, Response # type: ignore
except ImportError:
raise DidNotEnable("httpx is not installed")
__all__ = ["HttpxIntegration"]
class HttpxIntegration(Integration):
identifier = "httpx"
@staticmethod
def setup_once():
# type: () -> None
"""
httpx has its own transport layer and can be customized when needed,
so patch Client.send and AsyncClient.send to support both synchronous and async interfaces.
"""
_install_httpx_client()
_install_httpx_async_client()
def _install_httpx_client():
# type: () -> None
real_send = Client.send
def send(self, request, **kwargs):
# type: (Client, Request, **Any) -> Response
hub = Hub.current
if hub.get_integration(HttpxIntegration) is None:
return real_send(self, request, **kwargs)
parsed_url = parse_url(str(request.url), sanitize=False)
with hub.start_span(
op=OP.HTTP_CLIENT,
description="%s %s" % (request.method, parsed_url.url),
) as span:
span.set_data(SPANDATA.HTTP_METHOD, request.method)
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(hub, str(request.url)):
for key, value in hub.iter_trace_propagation_headers():
logger.debug(
"[Tracing] Adding `{key}` header {value} to outgoing request to {url}.".format(
key=key, value=value, url=request.url
)
)
request.headers[key] = value
rv = real_send(self, request, **kwargs)
span.set_http_status(rv.status_code)
span.set_data("reason", rv.reason_phrase)
return rv
Client.send = send
def _install_httpx_async_client():
# type: () -> None
real_send = AsyncClient.send
async def send(self, request, **kwargs):
# type: (AsyncClient, Request, **Any) -> Response
hub = Hub.current
if hub.get_integration(HttpxIntegration) is None:
return await real_send(self, request, **kwargs)
parsed_url = parse_url(str(request.url), sanitize=False)
with hub.start_span(
op=OP.HTTP_CLIENT,
description="%s %s" % (request.method, parsed_url.url),
) as span:
span.set_data(SPANDATA.HTTP_METHOD, request.method)
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(hub, str(request.url)):
for key, value in hub.iter_trace_propagation_headers():
logger.debug(
"[Tracing] Adding `{key}` header {value} to outgoing request to {url}.".format(
key=key, value=value, url=request.url
)
)
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)
return rv
AsyncClient.send = send