mirror of
https://github.com/open-telemetry/opentelemetry-python-contrib.git
synced 2025-07-28 12:43:39 +08:00
Support PEP 561 to opentelemetry-util-http
(#3127)
This commit is contained in:

committed by
GitHub

parent
cf6d45e96c
commit
9af3136e7f
@ -27,6 +27,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
([#3148](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3148))
|
([#3148](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3148))
|
||||||
- add support to Python 3.13
|
- add support to Python 3.13
|
||||||
([#3134](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3134))
|
([#3134](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3134))
|
||||||
|
- `opentelemetry-util-http` Add `py.typed` file to enable PEP 561
|
||||||
|
([#3127](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3127))
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ from os import environ
|
|||||||
from re import IGNORECASE as RE_IGNORECASE
|
from re import IGNORECASE as RE_IGNORECASE
|
||||||
from re import compile as re_compile
|
from re import compile as re_compile
|
||||||
from re import search
|
from re import search
|
||||||
from typing import Callable, Iterable, Optional
|
from typing import Callable, Iterable
|
||||||
from urllib.parse import urlparse, urlunparse
|
from urllib.parse import urlparse, urlunparse
|
||||||
|
|
||||||
from opentelemetry.semconv.trace import SpanAttributes
|
from opentelemetry.semconv.trace import SpanAttributes
|
||||||
@ -121,18 +121,16 @@ class SanitizeValue:
|
|||||||
_root = r"OTEL_PYTHON_{}"
|
_root = r"OTEL_PYTHON_{}"
|
||||||
|
|
||||||
|
|
||||||
def get_traced_request_attrs(instrumentation):
|
def get_traced_request_attrs(instrumentation: str) -> list[str]:
|
||||||
traced_request_attrs = environ.get(
|
traced_request_attrs = environ.get(
|
||||||
_root.format(f"{instrumentation}_TRACED_REQUEST_ATTRS"), []
|
_root.format(f"{instrumentation}_TRACED_REQUEST_ATTRS")
|
||||||
)
|
)
|
||||||
|
|
||||||
if traced_request_attrs:
|
if traced_request_attrs:
|
||||||
traced_request_attrs = [
|
return [
|
||||||
traced_request_attr.strip()
|
traced_request_attr.strip()
|
||||||
for traced_request_attr in traced_request_attrs.split(",")
|
for traced_request_attr in traced_request_attrs.split(",")
|
||||||
]
|
]
|
||||||
|
return []
|
||||||
return traced_request_attrs
|
|
||||||
|
|
||||||
|
|
||||||
def get_excluded_urls(instrumentation: str) -> ExcludeList:
|
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}"
|
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:
|
if method is None:
|
||||||
return None
|
return None
|
||||||
method = method.upper()
|
method = method.upper()
|
||||||
|
@ -17,12 +17,14 @@ This library provides functionality to enrich HTTP client spans with IPs. It doe
|
|||||||
not create spans on its own.
|
not create spans on its own.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import http.client
|
import http.client
|
||||||
import logging
|
import logging
|
||||||
import socket # pylint:disable=unused-import # Used for typing
|
import socket # pylint:disable=unused-import # Used for typing
|
||||||
import typing
|
import typing
|
||||||
from typing import Collection
|
from typing import Any, Callable, Collection, TypedDict, cast
|
||||||
|
|
||||||
import wrapt
|
import wrapt
|
||||||
|
|
||||||
@ -36,20 +38,22 @@ _STATE_KEY = "httpbase_instrumentation_state"
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
R = typing.TypeVar("R")
|
||||||
|
|
||||||
|
|
||||||
class HttpClientInstrumentor(BaseInstrumentor):
|
class HttpClientInstrumentor(BaseInstrumentor):
|
||||||
def instrumentation_dependencies(self) -> Collection[str]:
|
def instrumentation_dependencies(self) -> Collection[str]:
|
||||||
return () # This instruments http.client from stdlib; no extra deps.
|
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)"""
|
"""Instruments the http.client module (not creating spans on its own)"""
|
||||||
_instrument()
|
_instrument()
|
||||||
|
|
||||||
def _uninstrument(self, **kwargs):
|
def _uninstrument(self, **kwargs: Any):
|
||||||
_uninstrument()
|
_uninstrument()
|
||||||
|
|
||||||
|
|
||||||
def _remove_nonrecording(spanlist: typing.List[Span]):
|
def _remove_nonrecording(spanlist: list[Span]) -> bool:
|
||||||
idx = len(spanlist) - 1
|
idx = len(spanlist) - 1
|
||||||
while idx >= 0:
|
while idx >= 0:
|
||||||
if not spanlist[idx].is_recording():
|
if not spanlist[idx].is_recording():
|
||||||
@ -67,7 +71,9 @@ def _remove_nonrecording(spanlist: typing.List[Span]):
|
|||||||
return True
|
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
|
"""Tries to set the net.peer.ip semantic attribute on the current span from the given
|
||||||
HttpConnection.
|
HttpConnection.
|
||||||
|
|
||||||
@ -110,14 +116,17 @@ def trysetip(conn: http.client.HTTPConnection, loglevel=logging.DEBUG) -> bool:
|
|||||||
|
|
||||||
|
|
||||||
def _instrumented_connect(
|
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)
|
result = wrapped(*args, **kwargs)
|
||||||
trysetip(instance, loglevel=logging.WARNING)
|
trysetip(instance, loglevel=logging.WARNING)
|
||||||
return result
|
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."""
|
"""Instrument additional connect() methods, e.g. for derived classes."""
|
||||||
|
|
||||||
wrapt.wrap_function_wrapper(
|
wrapt.wrap_function_wrapper(
|
||||||
@ -129,8 +138,11 @@ def instrument_connect(module, name="connect"):
|
|||||||
|
|
||||||
def _instrument():
|
def _instrument():
|
||||||
def instrumented_send(
|
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)
|
done = trysetip(instance)
|
||||||
result = wrapped(*args, **kwargs)
|
result = wrapped(*args, **kwargs)
|
||||||
if not done:
|
if not done:
|
||||||
@ -147,8 +159,12 @@ def _instrument():
|
|||||||
# No need to instrument HTTPSConnection, as it calls super().connect()
|
# No need to instrument HTTPSConnection, as it calls super().connect()
|
||||||
|
|
||||||
|
|
||||||
def _getstate() -> typing.Optional[dict]:
|
class _ConnectionState(TypedDict):
|
||||||
return context.get_value(_STATE_KEY)
|
need_ip: list[Span]
|
||||||
|
|
||||||
|
|
||||||
|
def _getstate() -> _ConnectionState | None:
|
||||||
|
return cast(_ConnectionState, context.get_value(_STATE_KEY))
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
@ -163,7 +179,7 @@ def set_ip_on_next_http_connection(span: Span):
|
|||||||
finally:
|
finally:
|
||||||
context.detach(token)
|
context.detach(token)
|
||||||
else:
|
else:
|
||||||
spans: typing.List[Span] = state["need_ip"]
|
spans = state["need_ip"]
|
||||||
spans.append(span)
|
spans.append(span)
|
||||||
try:
|
try:
|
||||||
yield
|
yield
|
||||||
|
Reference in New Issue
Block a user