From a8990dbe3f820af7ce2ad516e019d391d188446c Mon Sep 17 00:00:00 2001 From: macieyn Date: Tue, 24 Jan 2023 17:54:17 +0100 Subject: [PATCH 1/5] enhance httpx tracing --- contrib/opencensus-ext-httpx/opencensus/ext/httpx/trace.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/opencensus-ext-httpx/opencensus/ext/httpx/trace.py b/contrib/opencensus-ext-httpx/opencensus/ext/httpx/trace.py index b77f29630..855244b5a 100644 --- a/contrib/opencensus-ext-httpx/opencensus/ext/httpx/trace.py +++ b/contrib/opencensus-ext-httpx/opencensus/ext/httpx/trace.py @@ -41,7 +41,7 @@ def trace_integration(tracer=None): execution_context.set_opencensus_tracer(tracer) wrapt.wrap_function_wrapper( - MODULE_NAME, "Client.request", wrap_client_request + MODULE_NAME, "Client.send", wrap_client_request ) # pylint: disable=protected-access integrations.add_integration(integrations._Integrations.HTTPX) From 74c192ce5ec8d203b122c812393e7de4df8eaa3e Mon Sep 17 00:00:00 2001 From: macieyn Date: Tue, 24 Jan 2023 18:06:26 +0100 Subject: [PATCH 2/5] update tests --- .../tests/test_httpx_trace.py | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/contrib/opencensus-ext-httpx/tests/test_httpx_trace.py b/contrib/opencensus-ext-httpx/tests/test_httpx_trace.py index ddb9cb87f..e360b5d21 100644 --- a/contrib/opencensus-ext-httpx/tests/test_httpx_trace.py +++ b/contrib/opencensus-ext-httpx/tests/test_httpx_trace.py @@ -37,7 +37,7 @@ def test_trace_integration(self): noop_tracer.NoopTracer, ) mock_wrap.assert_called_once_with( - trace.MODULE_NAME, "Client.request", trace.wrap_client_request + trace.MODULE_NAME, "Client.send", trace.wrap_client_request ) def test_trace_integration_set_tracer(self): @@ -54,7 +54,7 @@ class TmpTracer(noop_tracer.NoopTracer): execution_context.get_opencensus_tracer(), TmpTracer ) mock_wrap.assert_called_once_with( - trace.MODULE_NAME, "Client.request", trace.wrap_client_request + trace.MODULE_NAME, "Client.send", trace.wrap_client_request ) def test_wrap_client_request(self): @@ -81,7 +81,7 @@ def test_wrap_client_request(self): with patch, patch_thread: trace.wrap_client_request( - wrapped, "Client.request", (request_method, url), kwargs + wrapped, "Client.send", (request_method, url), kwargs ) expected_attributes = { @@ -137,7 +137,7 @@ def wrapped(*args, **kwargs): with patch_tracer, patch_attr, patch_thread: trace.wrap_client_request( - wrapped, "Client.request", (request_method, url), {} + wrapped, "Client.send", (request_method, url), {} ) expected_name = "/" @@ -170,7 +170,7 @@ def wrapped(*args, **kwargs): with patch_tracer, patch_attr, patch_thread: trace.wrap_client_request( - wrapped, "Client.request", (request_method, url), {} + wrapped, "Client.send", (request_method, url), {} ) self.assertEqual(None, mock_tracer.current_span) @@ -202,7 +202,7 @@ def wrapped(*args, **kwargs): with patch_tracer, patch_attr, patch_thread: trace.wrap_client_request( - wrapped, "Client.request", (request_method, url), {} + wrapped, "Client.send", (request_method, url), {} ) self.assertEqual(None, mock_tracer.current_span) @@ -230,7 +230,7 @@ def test_header_is_passed_in(self): with patch, patch_thread: trace.wrap_client_request( - wrapped, "Client.request", (request_method, url), kwargs + wrapped, "Client.send", (request_method, url), kwargs ) self.assertEqual(kwargs["headers"]["x-trace"], "some-value") @@ -258,7 +258,7 @@ def test_headers_are_preserved(self): with patch, patch_thread: trace.wrap_client_request( - wrapped, "Client.request", (request_method, url), kwargs + wrapped, "Client.send", (request_method, url), kwargs ) self.assertEqual(kwargs["headers"]["key"], "value") @@ -288,7 +288,7 @@ def test_tracer_headers_are_overwritten(self): with patch, patch_thread: trace.wrap_client_request( - wrapped, "Client.request", (request_method, url), kwargs + wrapped, "Client.send", (request_method, url), kwargs ) self.assertEqual(kwargs["headers"]["x-trace"], "some-value") @@ -320,7 +320,7 @@ def test_wrap_client_request_timeout(self): with self.assertRaises(httpx.TimeoutException): # breakpoint() trace.wrap_client_request( - wrapped, "Client.request", (request_method, url), kwargs + wrapped, "Client.send", (request_method, url), kwargs ) expected_attributes = { @@ -371,7 +371,7 @@ def test_wrap_client_request_invalid_url(self): with patch, patch_thread: with self.assertRaises(httpx.InvalidURL): trace.wrap_client_request( - wrapped, "Client.request", (request_method, url), kwargs + wrapped, "Client.send", (request_method, url), kwargs ) expected_attributes = { @@ -422,7 +422,7 @@ def test_wrap_client_request_exception(self): with patch, patch_thread: with self.assertRaises(httpx.TooManyRedirects): trace.wrap_client_request( - wrapped, "Client.request", (request_method, url), kwargs + wrapped, "Client.send", (request_method, url), kwargs ) expected_attributes = { From fa7c324b162a46268153370a3b485205a54b6b98 Mon Sep 17 00:00:00 2001 From: macieyn Date: Tue, 24 Jan 2023 18:25:01 +0100 Subject: [PATCH 3/5] update tests again --- .../tests/test_httpx_trace.py | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/contrib/opencensus-ext-httpx/tests/test_httpx_trace.py b/contrib/opencensus-ext-httpx/tests/test_httpx_trace.py index e360b5d21..61b821c5b 100644 --- a/contrib/opencensus-ext-httpx/tests/test_httpx_trace.py +++ b/contrib/opencensus-ext-httpx/tests/test_httpx_trace.py @@ -78,10 +78,11 @@ def test_wrap_client_request(self): url = "http://localhost:8080/test" request_method = "POST" kwargs = {} + request = httpx.Request(request_method, url, **kwargs) with patch, patch_thread: trace.wrap_client_request( - wrapped, "Client.send", (request_method, url), kwargs + wrapped, "Client.send", (request,), {} ) expected_attributes = { @@ -134,10 +135,11 @@ def wrapped(*args, **kwargs): url = "http://localhost/" request_method = "POST" + request = httpx.Request(request_method, url) with patch_tracer, patch_attr, patch_thread: trace.wrap_client_request( - wrapped, "Client.send", (request_method, url), {} + wrapped, "Client.send", (request,), {} ) expected_name = "/" @@ -167,10 +169,11 @@ def wrapped(*args, **kwargs): url = "http://localhost:8080" request_method = "POST" + request = httpx.Request(request_method, url) with patch_tracer, patch_attr, patch_thread: trace.wrap_client_request( - wrapped, "Client.send", (request_method, url), {} + wrapped, "Client.send", (request,), {} ) self.assertEqual(None, mock_tracer.current_span) @@ -199,10 +202,11 @@ def wrapped(*args, **kwargs): url = "http://localhost:8080" request_method = "POST" + request = httpx.Request(request_method, url) with patch_tracer, patch_attr, patch_thread: trace.wrap_client_request( - wrapped, "Client.send", (request_method, url), {} + wrapped, "Client.send", (request,), {} ) self.assertEqual(None, mock_tracer.current_span) @@ -227,10 +231,11 @@ def test_header_is_passed_in(self): url = "http://localhost:8080" request_method = "POST" kwargs = {} + request = httpx.Request(request_method, url, **kwargs) with patch, patch_thread: trace.wrap_client_request( - wrapped, "Client.send", (request_method, url), kwargs + wrapped, "Client.send", (request,), {} ) self.assertEqual(kwargs["headers"]["x-trace"], "some-value") @@ -255,10 +260,11 @@ def test_headers_are_preserved(self): url = "http://localhost:8080" request_method = "POST" kwargs = {"headers": {"key": "value"}} + request = httpx.Request(request_method, url, **kwargs) with patch, patch_thread: trace.wrap_client_request( - wrapped, "Client.send", (request_method, url), kwargs + wrapped, "Client.send", (request,), {} ) self.assertEqual(kwargs["headers"]["key"], "value") @@ -285,10 +291,11 @@ def test_tracer_headers_are_overwritten(self): url = "http://localhost:8080" request_method = "POST" kwargs = {"headers": {"x-trace": "original-value"}} + request = httpx.Request(request_method, url, **kwargs) with patch, patch_thread: trace.wrap_client_request( - wrapped, "Client.send", (request_method, url), kwargs + wrapped, "Client.send", (request,), {} ) self.assertEqual(kwargs["headers"]["x-trace"], "some-value") @@ -315,12 +322,13 @@ def test_wrap_client_request_timeout(self): url = "http://localhost:8080/test" request_method = "POST" kwargs = {} + request = httpx.Request(request_method, url, **kwargs) with patch, patch_thread: with self.assertRaises(httpx.TimeoutException): # breakpoint() trace.wrap_client_request( - wrapped, "Client.send", (request_method, url), kwargs + wrapped, "Client.send", (request,), {} ) expected_attributes = { @@ -367,11 +375,12 @@ def test_wrap_client_request_invalid_url(self): url = "http://localhost:8080/test" request_method = "POST" kwargs = {} + request = httpx.Request(request_method, url, **kwargs) with patch, patch_thread: with self.assertRaises(httpx.InvalidURL): trace.wrap_client_request( - wrapped, "Client.send", (request_method, url), kwargs + wrapped, "Client.send", (request,), {} ) expected_attributes = { @@ -418,11 +427,12 @@ def test_wrap_client_request_exception(self): url = "http://localhost:8080/test" request_method = "POST" kwargs = {} + request = httpx.Request(request_method, url, **kwargs) with patch, patch_thread: with self.assertRaises(httpx.TooManyRedirects): trace.wrap_client_request( - wrapped, "Client.send", (request_method, url), kwargs + wrapped, "Client.send", (request,), {} ) expected_attributes = { From 0234cc051b649e1073a39ac59783c9c6797008fc Mon Sep 17 00:00:00 2001 From: macieyn Date: Thu, 26 Jan 2023 11:17:32 +0100 Subject: [PATCH 4/5] update changelog --- contrib/opencensus-ext-httpx/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contrib/opencensus-ext-httpx/CHANGELOG.md b/contrib/opencensus-ext-httpx/CHANGELOG.md index 755e63048..1ae57f6a3 100644 --- a/contrib/opencensus-ext-httpx/CHANGELOG.md +++ b/contrib/opencensus-ext-httpx/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +- Allow tracing for `Advanced Usage` of httpx ([#1186](https://github.com/census-instrumentation/opencensus-python/pull/1186)) + ## 0.1.0 Released 2023-01-18 From 18899c861e7595d82d068fdbeb2f90c96eb5b065 Mon Sep 17 00:00:00 2001 From: macieyn Date: Fri, 3 Feb 2023 17:12:54 +0100 Subject: [PATCH 5/5] reimplement tracing and update tests --- .../opencensus/ext/httpx/trace.py | 22 ++++---- .../tests/test_httpx_trace.py | 53 +++++++++---------- 2 files changed, 35 insertions(+), 40 deletions(-) diff --git a/contrib/opencensus-ext-httpx/opencensus/ext/httpx/trace.py b/contrib/opencensus-ext-httpx/opencensus/ext/httpx/trace.py index 855244b5a..2c1008383 100644 --- a/contrib/opencensus-ext-httpx/opencensus/ext/httpx/trace.py +++ b/contrib/opencensus-ext-httpx/opencensus/ext/httpx/trace.py @@ -41,33 +41,33 @@ def trace_integration(tracer=None): execution_context.set_opencensus_tracer(tracer) wrapt.wrap_function_wrapper( - MODULE_NAME, "Client.send", wrap_client_request + MODULE_NAME, "Client.send", wrap_client_send ) # pylint: disable=protected-access integrations.add_integration(integrations._Integrations.HTTPX) -def wrap_client_request(wrapped, instance, args, kwargs): +def wrap_client_send(wrapped, instance, args, kwargs): """Wrap the session function to trace it.""" # Check if request was sent from an exporter. If so, do not wrap. if execution_context.is_exporter(): return wrapped(*args, **kwargs) - method = kwargs.get("method") or args[0] - url = kwargs.get("url") or args[1] - + request: httpx.Request = kwargs.get("request") or args[0] + method = request.method + url: httpx.URL = request.url + excludelist_hostnames = execution_context.get_opencensus_attr( "excludelist_hostnames" ) - parsed_url = urlparse(url) - if parsed_url.port is None: - dest_url = parsed_url.hostname + if url.port is None: + dest_url = url.host else: - dest_url = "{}:{}".format(parsed_url.hostname, parsed_url.port) + dest_url = "{}:{}".format(url.host, url.port) if utils.disable_tracing_hostname(dest_url, excludelist_hostnames): return wrapped(*args, **kwargs) - path = parsed_url.path if parsed_url.path else "/" + path = url.path if url.path else "/" _tracer = execution_context.get_opencensus_tracer() _span = _tracer.start_span() @@ -77,7 +77,7 @@ def wrap_client_request(wrapped, instance, args, kwargs): try: tracer_headers = _tracer.propagator.to_headers(_tracer.span_context) - kwargs.setdefault("headers", {}).update(tracer_headers) + request.headers.update(tracer_headers) except Exception: # pragma: NO COVER pass diff --git a/contrib/opencensus-ext-httpx/tests/test_httpx_trace.py b/contrib/opencensus-ext-httpx/tests/test_httpx_trace.py index 61b821c5b..d13812ec9 100644 --- a/contrib/opencensus-ext-httpx/tests/test_httpx_trace.py +++ b/contrib/opencensus-ext-httpx/tests/test_httpx_trace.py @@ -37,7 +37,7 @@ def test_trace_integration(self): noop_tracer.NoopTracer, ) mock_wrap.assert_called_once_with( - trace.MODULE_NAME, "Client.send", trace.wrap_client_request + trace.MODULE_NAME, "Client.send", trace.wrap_client_send ) def test_trace_integration_set_tracer(self): @@ -54,7 +54,7 @@ class TmpTracer(noop_tracer.NoopTracer): execution_context.get_opencensus_tracer(), TmpTracer ) mock_wrap.assert_called_once_with( - trace.MODULE_NAME, "Client.send", trace.wrap_client_request + trace.MODULE_NAME, "Client.send", trace.wrap_client_send ) def test_wrap_client_request(self): @@ -77,11 +77,10 @@ def test_wrap_client_request(self): url = "http://localhost:8080/test" request_method = "POST" - kwargs = {} - request = httpx.Request(request_method, url, **kwargs) + request = httpx.Request(request_method, url) with patch, patch_thread: - trace.wrap_client_request( + trace.wrap_client_send( wrapped, "Client.send", (request,), {} ) @@ -102,7 +101,7 @@ def test_wrap_client_request(self): self.assertEqual( expected_attributes, mock_tracer.current_span.attributes ) - self.assertEqual(kwargs["headers"]["x-trace"], "some-value") + self.assertEqual(request.headers["x-trace"], "some-value") self.assertEqual(expected_name, mock_tracer.current_span.name) self.assertEqual( expected_status.__dict__, mock_tracer.current_span.status.__dict__ @@ -138,7 +137,7 @@ def wrapped(*args, **kwargs): request = httpx.Request(request_method, url) with patch_tracer, patch_attr, patch_thread: - trace.wrap_client_request( + trace.wrap_client_send( wrapped, "Client.send", (request,), {} ) @@ -172,7 +171,7 @@ def wrapped(*args, **kwargs): request = httpx.Request(request_method, url) with patch_tracer, patch_attr, patch_thread: - trace.wrap_client_request( + trace.wrap_client_send( wrapped, "Client.send", (request,), {} ) @@ -205,7 +204,7 @@ def wrapped(*args, **kwargs): request = httpx.Request(request_method, url) with patch_tracer, patch_attr, patch_thread: - trace.wrap_client_request( + trace.wrap_client_send( wrapped, "Client.send", (request,), {} ) @@ -230,15 +229,14 @@ def test_header_is_passed_in(self): url = "http://localhost:8080" request_method = "POST" - kwargs = {} - request = httpx.Request(request_method, url, **kwargs) + request = httpx.Request(request_method, url) with patch, patch_thread: - trace.wrap_client_request( + trace.wrap_client_send( wrapped, "Client.send", (request,), {} ) - self.assertEqual(kwargs["headers"]["x-trace"], "some-value") + self.assertEqual(request.headers["x-trace"], "some-value") def test_headers_are_preserved(self): wrapped = mock.Mock(return_value=mock.Mock(status_code=200)) @@ -263,12 +261,12 @@ def test_headers_are_preserved(self): request = httpx.Request(request_method, url, **kwargs) with patch, patch_thread: - trace.wrap_client_request( + trace.wrap_client_send( wrapped, "Client.send", (request,), {} ) self.assertEqual(kwargs["headers"]["key"], "value") - self.assertEqual(kwargs["headers"]["x-trace"], "some-value") + self.assertEqual(request.headers["x-trace"], "some-value") def test_tracer_headers_are_overwritten(self): wrapped = mock.Mock(return_value=mock.Mock(status_code=200)) @@ -294,11 +292,11 @@ def test_tracer_headers_are_overwritten(self): request = httpx.Request(request_method, url, **kwargs) with patch, patch_thread: - trace.wrap_client_request( + trace.wrap_client_send( wrapped, "Client.send", (request,), {} ) - self.assertEqual(kwargs["headers"]["x-trace"], "some-value") + self.assertEqual(request.headers["x-trace"], "some-value") def test_wrap_client_request_timeout(self): wrapped = mock.Mock(return_value=mock.Mock(status_code=200)) @@ -321,13 +319,12 @@ def test_wrap_client_request_timeout(self): url = "http://localhost:8080/test" request_method = "POST" - kwargs = {} - request = httpx.Request(request_method, url, **kwargs) + request = httpx.Request(request_method, url) with patch, patch_thread: with self.assertRaises(httpx.TimeoutException): # breakpoint() - trace.wrap_client_request( + trace.wrap_client_send( wrapped, "Client.send", (request,), {} ) @@ -347,7 +344,7 @@ def test_wrap_client_request_timeout(self): self.assertEqual( expected_attributes, mock_tracer.current_span.attributes ) - self.assertEqual(kwargs["headers"]["x-trace"], "some-value") + self.assertEqual(request.headers["x-trace"], "some-value") self.assertEqual(expected_name, mock_tracer.current_span.name) self.assertEqual( expected_status.__dict__, mock_tracer.current_span.status.__dict__ @@ -374,12 +371,11 @@ def test_wrap_client_request_invalid_url(self): url = "http://localhost:8080/test" request_method = "POST" - kwargs = {} - request = httpx.Request(request_method, url, **kwargs) + request = httpx.Request(request_method, url) with patch, patch_thread: with self.assertRaises(httpx.InvalidURL): - trace.wrap_client_request( + trace.wrap_client_send( wrapped, "Client.send", (request,), {} ) @@ -399,7 +395,7 @@ def test_wrap_client_request_invalid_url(self): self.assertEqual( expected_attributes, mock_tracer.current_span.attributes ) - self.assertEqual(kwargs["headers"]["x-trace"], "some-value") + self.assertEqual(request.headers["x-trace"], "some-value") self.assertEqual(expected_name, mock_tracer.current_span.name) self.assertEqual( expected_status.__dict__, mock_tracer.current_span.status.__dict__ @@ -426,12 +422,11 @@ def test_wrap_client_request_exception(self): url = "http://localhost:8080/test" request_method = "POST" - kwargs = {} - request = httpx.Request(request_method, url, **kwargs) + request = httpx.Request(request_method, url) with patch, patch_thread: with self.assertRaises(httpx.TooManyRedirects): - trace.wrap_client_request( + trace.wrap_client_send( wrapped, "Client.send", (request,), {} ) @@ -451,7 +446,7 @@ def test_wrap_client_request_exception(self): self.assertEqual( expected_attributes, mock_tracer.current_span.attributes ) - self.assertEqual(kwargs["headers"]["x-trace"], "some-value") + self.assertEqual(request.headers["x-trace"], "some-value") self.assertEqual(expected_name, mock_tracer.current_span.name) self.assertEqual( expected_status.__dict__, mock_tracer.current_span.status.__dict__