feat(urllib3)!: refactor request hook parameters (#2711)
This commit is contained in:
parent
6690ecc441
commit
4f985196c6
|
|
@ -67,6 +67,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
([#2726](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2726))
|
([#2726](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2726))
|
||||||
- `opentelemetry-instrumentation-fastapi` Add dependency support for fastapi-slim
|
- `opentelemetry-instrumentation-fastapi` Add dependency support for fastapi-slim
|
||||||
([#2702](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2702))
|
([#2702](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2702))
|
||||||
|
- `opentelemetry-instrumentation-urllib3` improve request_hook, replacing `headers` and `body` parameters with a single `request_info: RequestInfo` parameter that now contains the `method` and `url` ([#2711](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2711))
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,14 +47,19 @@ The hooks can be configured as follows:
|
||||||
|
|
||||||
.. code:: python
|
.. code:: python
|
||||||
|
|
||||||
# `request` is an instance of urllib3.connectionpool.HTTPConnectionPool
|
def request_hook(
|
||||||
def request_hook(span, request):
|
span: Span,
|
||||||
pass
|
pool: urllib3.connectionpool.HTTPConnectionPool,
|
||||||
|
request_info: RequestInfo,
|
||||||
|
) -> Any:
|
||||||
|
...
|
||||||
|
|
||||||
# `request` is an instance of urllib3.connectionpool.HTTPConnectionPool
|
def response_hook(
|
||||||
# `response` is an instance of urllib3.response.HTTPResponse
|
span: Span,
|
||||||
def response_hook(span, request, response):
|
pool: urllib3.connectionpool.HTTPConnectionPool,
|
||||||
pass
|
response: urllib3.response.HTTPResponse,
|
||||||
|
) -> Any:
|
||||||
|
...
|
||||||
|
|
||||||
URLLib3Instrumentor().instrument(
|
URLLib3Instrumentor().instrument(
|
||||||
request_hook=request_hook, response_hook=response_hook
|
request_hook=request_hook, response_hook=response_hook
|
||||||
|
|
@ -81,6 +86,7 @@ API
|
||||||
import collections.abc
|
import collections.abc
|
||||||
import io
|
import io
|
||||||
import typing
|
import typing
|
||||||
|
from dataclasses import dataclass
|
||||||
from timeit import default_timer
|
from timeit import default_timer
|
||||||
from typing import Collection
|
from typing import Collection
|
||||||
|
|
||||||
|
|
@ -135,14 +141,29 @@ from opentelemetry.util.http.httplib import set_ip_on_next_http_connection
|
||||||
|
|
||||||
_excluded_urls_from_env = get_excluded_urls("URLLIB3")
|
_excluded_urls_from_env = get_excluded_urls("URLLIB3")
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class RequestInfo:
|
||||||
|
"""Arguments that were passed to the ``urlopen()`` call."""
|
||||||
|
|
||||||
|
__slots__ = ("method", "url", "headers", "body")
|
||||||
|
|
||||||
|
# The type annotations here come from ``HTTPConnectionPool.urlopen()``.
|
||||||
|
method: str
|
||||||
|
url: str
|
||||||
|
headers: typing.Optional[typing.Mapping[str, str]]
|
||||||
|
body: typing.Union[
|
||||||
|
bytes, typing.IO[typing.Any], typing.Iterable[bytes], str, None
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
_UrlFilterT = typing.Optional[typing.Callable[[str], str]]
|
_UrlFilterT = typing.Optional[typing.Callable[[str], str]]
|
||||||
_RequestHookT = typing.Optional[
|
_RequestHookT = typing.Optional[
|
||||||
typing.Callable[
|
typing.Callable[
|
||||||
[
|
[
|
||||||
Span,
|
Span,
|
||||||
urllib3.connectionpool.HTTPConnectionPool,
|
urllib3.connectionpool.HTTPConnectionPool,
|
||||||
typing.Dict,
|
RequestInfo,
|
||||||
typing.Optional[str],
|
|
||||||
],
|
],
|
||||||
None,
|
None,
|
||||||
]
|
]
|
||||||
|
|
@ -317,7 +338,16 @@ def _instrument(
|
||||||
span_name, kind=SpanKind.CLIENT, attributes=span_attributes
|
span_name, kind=SpanKind.CLIENT, attributes=span_attributes
|
||||||
) as span, set_ip_on_next_http_connection(span):
|
) as span, set_ip_on_next_http_connection(span):
|
||||||
if callable(request_hook):
|
if callable(request_hook):
|
||||||
request_hook(span, instance, headers, body)
|
request_hook(
|
||||||
|
span,
|
||||||
|
instance,
|
||||||
|
RequestInfo(
|
||||||
|
method=method,
|
||||||
|
url=url,
|
||||||
|
headers=headers,
|
||||||
|
body=body,
|
||||||
|
),
|
||||||
|
)
|
||||||
inject(headers)
|
inject(headers)
|
||||||
# TODO: add error handling to also set exception `error.type` in new semconv
|
# TODO: add error handling to also set exception `error.type` in new semconv
|
||||||
with suppress_http_instrumentation():
|
with suppress_http_instrumentation():
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,10 @@ from opentelemetry.instrumentation._semconv import (
|
||||||
_HTTPStabilityMode,
|
_HTTPStabilityMode,
|
||||||
_OpenTelemetrySemanticConventionStability,
|
_OpenTelemetrySemanticConventionStability,
|
||||||
)
|
)
|
||||||
from opentelemetry.instrumentation.urllib3 import URLLib3Instrumentor
|
from opentelemetry.instrumentation.urllib3 import (
|
||||||
|
RequestInfo,
|
||||||
|
URLLib3Instrumentor,
|
||||||
|
)
|
||||||
from opentelemetry.instrumentation.utils import (
|
from opentelemetry.instrumentation.utils import (
|
||||||
suppress_http_instrumentation,
|
suppress_http_instrumentation,
|
||||||
suppress_instrumentation,
|
suppress_instrumentation,
|
||||||
|
|
@ -42,6 +45,7 @@ from opentelemetry.semconv.attributes.url_attributes import URL_FULL
|
||||||
from opentelemetry.semconv.trace import SpanAttributes
|
from opentelemetry.semconv.trace import SpanAttributes
|
||||||
from opentelemetry.test.mock_textmap import MockTextMapPropagator
|
from opentelemetry.test.mock_textmap import MockTextMapPropagator
|
||||||
from opentelemetry.test.test_base import TestBase
|
from opentelemetry.test.test_base import TestBase
|
||||||
|
from opentelemetry.trace import Span
|
||||||
from opentelemetry.util.http import get_excluded_urls
|
from opentelemetry.util.http import get_excluded_urls
|
||||||
|
|
||||||
# pylint: disable=too-many-public-methods
|
# pylint: disable=too-many-public-methods
|
||||||
|
|
@ -521,10 +525,10 @@ class TestURLLib3Instrumentor(TestBase):
|
||||||
self.assert_success_span(response, self.HTTP_URL)
|
self.assert_success_span(response, self.HTTP_URL)
|
||||||
|
|
||||||
def test_hooks(self):
|
def test_hooks(self):
|
||||||
def request_hook(span, request, body, headers):
|
def request_hook(span, pool, request_info):
|
||||||
span.update_name("name set from hook")
|
span.update_name("name set from hook")
|
||||||
|
|
||||||
def response_hook(span, request, response):
|
def response_hook(span, pool, response):
|
||||||
span.set_attribute("response_hook_attr", "value")
|
span.set_attribute("response_hook_attr", "value")
|
||||||
|
|
||||||
URLLib3Instrumentor().uninstrument()
|
URLLib3Instrumentor().uninstrument()
|
||||||
|
|
@ -541,11 +545,17 @@ class TestURLLib3Instrumentor(TestBase):
|
||||||
self.assertEqual(span.attributes["response_hook_attr"], "value")
|
self.assertEqual(span.attributes["response_hook_attr"], "value")
|
||||||
|
|
||||||
def test_request_hook_params(self):
|
def test_request_hook_params(self):
|
||||||
def request_hook(span, request, headers, body):
|
def request_hook(
|
||||||
|
span: Span,
|
||||||
|
_pool: urllib3.connectionpool.ConnectionPool,
|
||||||
|
request_info: RequestInfo,
|
||||||
|
) -> None:
|
||||||
|
span.set_attribute("request_hook_method", request_info.method)
|
||||||
|
span.set_attribute("request_hook_url", request_info.url)
|
||||||
span.set_attribute(
|
span.set_attribute(
|
||||||
"request_hook_headers", json.dumps(dict(headers))
|
"request_hook_headers", json.dumps(dict(request_info.headers))
|
||||||
)
|
)
|
||||||
span.set_attribute("request_hook_body", body)
|
span.set_attribute("request_hook_body", request_info.body)
|
||||||
|
|
||||||
URLLib3Instrumentor().uninstrument()
|
URLLib3Instrumentor().uninstrument()
|
||||||
URLLib3Instrumentor().instrument(
|
URLLib3Instrumentor().instrument(
|
||||||
|
|
@ -564,6 +574,10 @@ class TestURLLib3Instrumentor(TestBase):
|
||||||
|
|
||||||
span = self.assert_span()
|
span = self.assert_span()
|
||||||
|
|
||||||
|
self.assertEqual(span.attributes["request_hook_method"], "POST")
|
||||||
|
self.assertEqual(
|
||||||
|
span.attributes["request_hook_url"], "http://mock/status/200"
|
||||||
|
)
|
||||||
self.assertIn("request_hook_headers", span.attributes)
|
self.assertIn("request_hook_headers", span.attributes)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
span.attributes["request_hook_headers"], json.dumps(headers)
|
span.attributes["request_hook_headers"], json.dumps(headers)
|
||||||
|
|
@ -572,8 +586,12 @@ class TestURLLib3Instrumentor(TestBase):
|
||||||
self.assertEqual(span.attributes["request_hook_body"], body)
|
self.assertEqual(span.attributes["request_hook_body"], body)
|
||||||
|
|
||||||
def test_request_positional_body(self):
|
def test_request_positional_body(self):
|
||||||
def request_hook(span, request, headers, body):
|
def request_hook(
|
||||||
span.set_attribute("request_hook_body", body)
|
span: Span,
|
||||||
|
_pool: urllib3.connectionpool.ConnectionPool,
|
||||||
|
request_info: RequestInfo,
|
||||||
|
) -> None:
|
||||||
|
span.set_attribute("request_hook_body", request_info.body)
|
||||||
|
|
||||||
URLLib3Instrumentor().uninstrument()
|
URLLib3Instrumentor().uninstrument()
|
||||||
URLLib3Instrumentor().instrument(
|
URLLib3Instrumentor().instrument(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue