Skip to content

Commit

Permalink
Urllib3 request hook (#660)
Browse files Browse the repository at this point in the history
* Urllib3: extend request hook with request body and headers

* Change GET to POST in test_extended_request_hook

* added changelog entry

* update ExtendedReqeustHookT

* adding up to date generated code

* replace _RequestHookT with _ExtendedRequestHookT

* updated Changelog

Co-authored-by: Ran Nozik <ran@heliosphere.io>
  • Loading branch information
ItayGibel-helios and nozik authored Sep 13, 2021
1 parent fc8a02b commit b47328e
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 4 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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[
Expand Down Expand Up @@ -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 = {
Expand All @@ -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():
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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):
Expand All @@ -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&param2=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)

0 comments on commit b47328e

Please sign in to comment.