diff --git a/CHANGELOG.md b/CHANGELOG.md index e20fa06661..42168a6ce7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `opentelemetry-instrumentation-botocore` Fix span injection for lambda invoke ([#663](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/663)) +### Changed + +- `opentelemetry-instrumentation-urllib3` Updated `_RequestHookT` with two additional fields - the request body and the request headers +([#660](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/660)) + ## [1.5.0-0.24b0](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v1.5.0-0.24b0) - 2021-08-26 ### Added diff --git a/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/__init__.py b/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/__init__.py index 49d8a85b6b..240ab29477 100644 --- a/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/__init__.py @@ -90,7 +90,15 @@ def response_hook(span, request, response): _UrlFilterT = typing.Optional[typing.Callable[[str], str]] _RequestHookT = typing.Optional[ - typing.Callable[[Span, urllib3.connectionpool.HTTPConnectionPool], None] + typing.Callable[ + [ + Span, + urllib3.connectionpool.HTTPConnectionPool, + typing.Dict, + typing.Optional[str], + ], + None, + ] ] _ResponseHookT = typing.Optional[ typing.Callable[ @@ -150,6 +158,7 @@ def instrumented_urlopen(wrapped, instance, args, kwargs): method = _get_url_open_arg("method", args, kwargs).upper() url = _get_url(instance, args, kwargs, url_filter) headers = _prepare_headers(kwargs) + body = _get_url_open_arg("body", args, kwargs) span_name = "HTTP {}".format(method.strip()) span_attributes = { @@ -161,7 +170,7 @@ def instrumented_urlopen(wrapped, instance, args, kwargs): span_name, kind=SpanKind.CLIENT, attributes=span_attributes ) as span: if callable(request_hook): - request_hook(span, instance) + request_hook(span, instance, headers, body) inject(headers) with _suppress_further_instrumentation(): diff --git a/instrumentation/opentelemetry-instrumentation-urllib3/tests/test_urllib3_integration.py b/instrumentation/opentelemetry-instrumentation-urllib3/tests/test_urllib3_integration.py index 9e32162d34..d2893d037b 100644 --- a/instrumentation/opentelemetry-instrumentation-urllib3/tests/test_urllib3_integration.py +++ b/instrumentation/opentelemetry-instrumentation-urllib3/tests/test_urllib3_integration.py @@ -11,7 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - +import json import typing from unittest import mock @@ -45,6 +45,7 @@ def setUp(self): httpretty.enable(allow_net_connect=False) httpretty.register_uri(httpretty.GET, self.HTTP_URL, body="Hello!") httpretty.register_uri(httpretty.GET, self.HTTPS_URL, body="Hello!") + httpretty.register_uri(httpretty.POST, self.HTTP_URL, body="Hello!") def tearDown(self): super().tearDown() @@ -261,7 +262,7 @@ def test_credential_removal(self): self.assert_success_span(response, self.HTTP_URL) def test_hooks(self): - def request_hook(span, request): + def request_hook(span, request, body, headers): span.update_name("name set from hook") def response_hook(span, request, response): @@ -279,3 +280,30 @@ def response_hook(span, request, response): self.assertEqual(span.name, "name set from hook") self.assertIn("response_hook_attr", span.attributes) self.assertEqual(span.attributes["response_hook_attr"], "value") + + def test_request_hook_params(self): + def request_hook(span, request, headers, body): + span.set_attribute("request_hook_headers", json.dumps(headers)) + span.set_attribute("request_hook_body", body) + + URLLib3Instrumentor().uninstrument() + URLLib3Instrumentor().instrument(request_hook=request_hook,) + + headers = {"header1": "value1", "header2": "value2"} + body = "param1=1¶m2=2" + + pool = urllib3.HTTPConnectionPool("httpbin.org") + response = pool.request( + "POST", "/status/200", body=body, headers=headers + ) + + self.assertEqual(b"Hello!", response.data) + + span = self.assert_span() + + self.assertIn("request_hook_headers", span.attributes) + self.assertEqual( + span.attributes["request_hook_headers"], json.dumps(headers) + ) + self.assertIn("request_hook_body", span.attributes) + self.assertEqual(span.attributes["request_hook_body"], body)