Skip to content

Commit 67d736b

Browse files
committed
fix #3020
Signed-off-by: emdneto <[email protected]>
1 parent 23f67eb commit 67d736b

File tree

3 files changed

+73
-28
lines changed

3 files changed

+73
-28
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2222

2323
- `opentelemetry-instrumentation-httpx`: instrument_client is a static method again
2424
([#3003](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3003))
25+
- `opentelemetry-instrumentation-httpx`: Check if mount transport is none before wrap it
26+
([#3003](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3003))
2527

2628
### Breaking changes
2729

instrumentation/opentelemetry-instrumentation-httpx/src/opentelemetry/instrumentation/httpx/__init__.py

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,17 +1005,18 @@ def instrument_client(
10051005
),
10061006
)
10071007
for transport in client._mounts.values():
1008-
wrap_function_wrapper(
1009-
transport,
1010-
"handle_request",
1011-
partial(
1012-
cls._handle_request_wrapper,
1013-
tracer=tracer,
1014-
sem_conv_opt_in_mode=sem_conv_opt_in_mode,
1015-
request_hook=request_hook,
1016-
response_hook=response_hook,
1017-
),
1018-
)
1008+
if transport is not None:
1009+
wrap_function_wrapper(
1010+
transport,
1011+
"handle_request",
1012+
partial(
1013+
cls._handle_request_wrapper,
1014+
tracer=tracer,
1015+
sem_conv_opt_in_mode=sem_conv_opt_in_mode,
1016+
request_hook=request_hook,
1017+
response_hook=response_hook,
1018+
),
1019+
)
10191020
client._is_instrumented_by_opentelemetry = True
10201021
if hasattr(client._transport, "handle_async_request"):
10211022
wrap_function_wrapper(
@@ -1030,17 +1031,18 @@ def instrument_client(
10301031
),
10311032
)
10321033
for transport in client._mounts.values():
1033-
wrap_function_wrapper(
1034-
transport,
1035-
"handle_async_request",
1036-
partial(
1037-
cls._handle_async_request_wrapper,
1038-
tracer=tracer,
1039-
sem_conv_opt_in_mode=sem_conv_opt_in_mode,
1040-
async_request_hook=async_request_hook,
1041-
async_response_hook=async_response_hook,
1042-
),
1043-
)
1034+
if transport is not None:
1035+
wrap_function_wrapper(
1036+
transport,
1037+
"handle_async_request",
1038+
partial(
1039+
cls._handle_async_request_wrapper,
1040+
tracer=tracer,
1041+
sem_conv_opt_in_mode=sem_conv_opt_in_mode,
1042+
async_request_hook=async_request_hook,
1043+
async_response_hook=async_response_hook,
1044+
),
1045+
)
10441046
client._is_instrumented_by_opentelemetry = True
10451047

10461048
@staticmethod

instrumentation/opentelemetry-instrumentation-httpx/tests/test_httpx_integration.py

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -725,7 +725,6 @@ def test_client_mounts_with_instrumented_transport(self):
725725
spans[1].attributes[SpanAttributes.HTTP_URL], https_url
726726
)
727727

728-
@mock.patch.dict("os.environ", {"NO_PROXY": ""}, clear=True)
729728
class BaseInstrumentorTest(BaseTest, metaclass=abc.ABCMeta):
730729
@abc.abstractmethod
731730
def create_client(
@@ -741,6 +740,10 @@ def create_client(
741740
def create_proxy_transport(self, url: str):
742741
pass
743742

743+
@abc.abstractmethod
744+
def get_transport_handler(self, transport):
745+
pass
746+
744747
def setUp(self):
745748
super().setUp()
746749
self.client = self.create_client()
@@ -769,11 +772,9 @@ def assert_proxy_mounts(self, mounts, num_mounts, transport_type=None):
769772
transport_type,
770773
)
771774
else:
772-
handler = getattr(transport, "handle_request", None)
773-
if not handler:
774-
handler = getattr(
775-
transport, "handle_async_request"
776-
)
775+
if transport is None:
776+
continue
777+
handler = self.get_transport_handler(transport)
777778
self.assertTrue(
778779
isinstance(handler, ObjectProxy)
779780
and getattr(handler, "__wrapped__")
@@ -983,6 +984,21 @@ def test_uninstrument_new_client(self):
983984
self.assertEqual(result.text, "Hello!")
984985
self.assert_span()
985986

987+
@mock.patch.dict(
988+
"os.environ", {"NO_PROXY": "http://mock/status/200"}, clear=True
989+
)
990+
def test_instrument_with_no_proxy(self):
991+
proxy_mounts = self.create_proxy_mounts()
992+
HTTPXClientInstrumentor().instrument()
993+
client = self.create_client(mounts=proxy_mounts)
994+
self.perform_request(self.URL, client=client)
995+
self.assert_span(num_spans=1)
996+
print(client._mounts)
997+
self.assert_proxy_mounts(
998+
client._mounts.values(),
999+
3,
1000+
)
1001+
9861002
def test_instrument_proxy(self):
9871003
proxy_mounts = self.create_proxy_mounts()
9881004
HTTPXClientInstrumentor().instrument()
@@ -994,6 +1010,25 @@ def test_instrument_proxy(self):
9941010
2,
9951011
)
9961012

1013+
@mock.patch.dict("os.environ", {"NO_PROXY": "http://mock"}, clear=True)
1014+
def test_instrument_client_with_no_proxy(self):
1015+
proxy_mounts = self.create_proxy_mounts()
1016+
client = self.create_client(mounts=proxy_mounts)
1017+
self.assert_proxy_mounts(
1018+
client._mounts.values(),
1019+
3,
1020+
(httpx.HTTPTransport, httpx.AsyncHTTPTransport, type(None)),
1021+
)
1022+
HTTPXClientInstrumentor.instrument_client(client)
1023+
result = self.perform_request(self.URL, client=client)
1024+
self.assertEqual(result.text, "Hello!")
1025+
self.assert_span(num_spans=1)
1026+
self.assert_proxy_mounts(
1027+
client._mounts.values(),
1028+
3,
1029+
)
1030+
HTTPXClientInstrumentor().uninstrument_client(client)
1031+
9971032
def test_instrument_client_with_proxy(self):
9981033
proxy_mounts = self.create_proxy_mounts()
9991034
client = self.create_client(mounts=proxy_mounts)
@@ -1188,6 +1223,9 @@ def perform_request(
11881223
def create_proxy_transport(self, url):
11891224
return httpx.HTTPTransport(proxy=httpx.Proxy(url))
11901225

1226+
def get_transport_handler(self, transport):
1227+
return getattr(transport, "handle_request", None)
1228+
11911229
def test_can_instrument_subclassed_client(self):
11921230
class CustomClient(httpx.Client):
11931231
pass
@@ -1241,6 +1279,9 @@ async def _perform_request():
12411279
def create_proxy_transport(self, url):
12421280
return httpx.AsyncHTTPTransport(proxy=httpx.Proxy(url))
12431281

1282+
def get_transport_handler(self, transport):
1283+
return getattr(transport, "handle_async_request", None)
1284+
12441285
def test_basic_multiple(self):
12451286
# We need to create separate clients because in httpx >= 0.19,
12461287
# closing the client after "with" means the second http call fails

0 commit comments

Comments
 (0)