Source code for restgdf.telemetry._instrumentor
"""``RestgdfInstrumentor`` — dynamic subclass of ``AioHttpClientInstrumentor``.
The class is built lazily on first instantiation so that ``import
restgdf.telemetry`` succeeds without any OpenTelemetry packages installed.
If OTel is absent at *construction* time, :class:`~restgdf.errors.OptionalDependencyError`
is raised (R-58).
"""
from __future__ import annotations
from typing import Any
from restgdf.errors import OptionalDependencyError
[docs]
class RestgdfInstrumentor:
"""Thin restgdf-specific wrapper around ``AioHttpClientInstrumentor``.
Dynamically rebuilds itself as a subclass of
``opentelemetry.instrumentation.aiohttp_client.AioHttpClientInstrumentor``
at construction time. This deferred approach avoids import-time failures
on a base install that has no OTel packages.
"""
_real_cls: type | None = None
def __new__(cls, *args: Any, **kwargs: Any) -> RestgdfInstrumentor:
"""Build the dynamic subclass on first instantiation."""
if cls._real_cls is None:
try:
from opentelemetry.instrumentation.aiohttp_client import ( # type: ignore[import-untyped]
AioHttpClientInstrumentor,
)
except ImportError as exc:
raise OptionalDependencyError(
"restgdf[telemetry] requires opentelemetry-instrumentation-aiohttp-client. "
"Install it with: pip install restgdf[telemetry]",
) from exc
# Dynamically create a subclass that inherits from both
cls._real_cls = type(
"RestgdfInstrumentor",
(cls, AioHttpClientInstrumentor),
{},
)
instance: RestgdfInstrumentor = object.__new__(cls._real_cls)
return instance # type: ignore[return-value]
__all__ = ["RestgdfInstrumentor"]