From 21c546612c1e1537805bab4b416a49c60800827f Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Fri, 20 Dec 2024 18:27:21 +0100 Subject: [PATCH 1/2] Support PEP 561 to `opentelemetry-util-http` --- .../src/opentelemetry/util/http/__init__.py | 14 +++---- .../src/opentelemetry/util/http/httplib.py | 42 +++++++++++++------ .../src/opentelemetry/util/http/py.typed | 0 3 files changed, 35 insertions(+), 21 deletions(-) create mode 100644 util/opentelemetry-util-http/src/opentelemetry/util/http/py.typed diff --git a/util/opentelemetry-util-http/src/opentelemetry/util/http/__init__.py b/util/opentelemetry-util-http/src/opentelemetry/util/http/__init__.py index f5dacf0fff..c7dd9f7b06 100644 --- a/util/opentelemetry-util-http/src/opentelemetry/util/http/__init__.py +++ b/util/opentelemetry-util-http/src/opentelemetry/util/http/__init__.py @@ -19,7 +19,7 @@ from re import IGNORECASE as RE_IGNORECASE from re import compile as re_compile from re import search -from typing import Callable, Iterable, Optional +from typing import Callable, Iterable from urllib.parse import urlparse, urlunparse from opentelemetry.semconv.trace import SpanAttributes @@ -121,18 +121,16 @@ def sanitize_header_values( _root = r"OTEL_PYTHON_{}" -def get_traced_request_attrs(instrumentation): +def get_traced_request_attrs(instrumentation: str) -> list[str]: traced_request_attrs = environ.get( - _root.format(f"{instrumentation}_TRACED_REQUEST_ATTRS"), [] + _root.format(f"{instrumentation}_TRACED_REQUEST_ATTRS") ) - if traced_request_attrs: - traced_request_attrs = [ + return [ traced_request_attr.strip() for traced_request_attr in traced_request_attrs.split(",") ] - - return traced_request_attrs + return [] def get_excluded_urls(instrumentation: str) -> ExcludeList: @@ -193,7 +191,7 @@ def normalise_response_header_name(header: str) -> str: return f"http.response.header.{key}" -def sanitize_method(method: Optional[str]) -> Optional[str]: +def sanitize_method(method: str | None) -> str | None: if method is None: return None method = method.upper() diff --git a/util/opentelemetry-util-http/src/opentelemetry/util/http/httplib.py b/util/opentelemetry-util-http/src/opentelemetry/util/http/httplib.py index 3d6b875752..f375e2f7c8 100644 --- a/util/opentelemetry-util-http/src/opentelemetry/util/http/httplib.py +++ b/util/opentelemetry-util-http/src/opentelemetry/util/http/httplib.py @@ -17,12 +17,14 @@ not create spans on its own. """ +from __future__ import annotations + import contextlib import http.client import logging import socket # pylint:disable=unused-import # Used for typing import typing -from typing import Collection +from typing import Any, Callable, Collection, TypedDict, cast import wrapt @@ -36,20 +38,22 @@ logger = logging.getLogger(__name__) +R = typing.TypeVar("R") + class HttpClientInstrumentor(BaseInstrumentor): def instrumentation_dependencies(self) -> Collection[str]: return () # This instruments http.client from stdlib; no extra deps. - def _instrument(self, **kwargs): + def _instrument(self, **kwargs: Any): """Instruments the http.client module (not creating spans on its own)""" _instrument() - def _uninstrument(self, **kwargs): + def _uninstrument(self, **kwargs: Any): _uninstrument() -def _remove_nonrecording(spanlist: typing.List[Span]): +def _remove_nonrecording(spanlist: list[Span]) -> bool: idx = len(spanlist) - 1 while idx >= 0: if not spanlist[idx].is_recording(): @@ -67,7 +71,9 @@ def _remove_nonrecording(spanlist: typing.List[Span]): return True -def trysetip(conn: http.client.HTTPConnection, loglevel=logging.DEBUG) -> bool: +def trysetip( + conn: http.client.HTTPConnection, loglevel: int = logging.DEBUG +) -> bool: """Tries to set the net.peer.ip semantic attribute on the current span from the given HttpConnection. @@ -110,14 +116,17 @@ def trysetip(conn: http.client.HTTPConnection, loglevel=logging.DEBUG) -> bool: def _instrumented_connect( - wrapped, instance: http.client.HTTPConnection, args, kwargs -): + wrapped: Callable[..., R], + instance: http.client.HTTPConnection, + args: tuple[Any, ...], + kwargs: dict[str, Any], +) -> R: result = wrapped(*args, **kwargs) trysetip(instance, loglevel=logging.WARNING) return result -def instrument_connect(module, name="connect"): +def instrument_connect(module: type[Any], name: str = "connect"): """Instrument additional connect() methods, e.g. for derived classes.""" wrapt.wrap_function_wrapper( @@ -129,8 +138,11 @@ def instrument_connect(module, name="connect"): def _instrument(): def instrumented_send( - wrapped, instance: http.client.HTTPConnection, args, kwargs - ): + wrapped: Callable[..., R], + instance: http.client.HTTPConnection, + args: tuple[Any, ...], + kwargs: dict[str, Any], + ) -> R: done = trysetip(instance) result = wrapped(*args, **kwargs) if not done: @@ -147,8 +159,12 @@ def instrumented_send( # No need to instrument HTTPSConnection, as it calls super().connect() -def _getstate() -> typing.Optional[dict]: - return context.get_value(_STATE_KEY) +class _ConnectionState(TypedDict): + need_ip: list[Span] + + +def _getstate() -> _ConnectionState | None: + return cast(_ConnectionState, context.get_value(_STATE_KEY)) @contextlib.contextmanager @@ -163,7 +179,7 @@ def set_ip_on_next_http_connection(span: Span): finally: context.detach(token) else: - spans: typing.List[Span] = state["need_ip"] + spans = state["need_ip"] spans.append(span) try: yield diff --git a/util/opentelemetry-util-http/src/opentelemetry/util/http/py.typed b/util/opentelemetry-util-http/src/opentelemetry/util/http/py.typed new file mode 100644 index 0000000000..e69de29bb2 From 2ea4242f52a464b3a63345447250add3d06d5a13 Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Fri, 20 Dec 2024 18:34:13 +0100 Subject: [PATCH 2/2] Add changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a243091b1d..a6c91c5655 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#3100](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3100)) - Add support to database stability opt-in in `_semconv` utilities and add tests ([#3111](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3111)) +- `opentelemetry-util-http` Add `py.typed` file to enable PEP 561 + ([#3127](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3127)) ### Fixed