diff options
Diffstat (limited to 'venv/lib/python3.11/site-packages/litestar/contrib/opentelemetry')
8 files changed, 197 insertions, 0 deletions
diff --git a/venv/lib/python3.11/site-packages/litestar/contrib/opentelemetry/__init__.py b/venv/lib/python3.11/site-packages/litestar/contrib/opentelemetry/__init__.py new file mode 100644 index 0000000..3f93611 --- /dev/null +++ b/venv/lib/python3.11/site-packages/litestar/contrib/opentelemetry/__init__.py @@ -0,0 +1,4 @@ +from .config import OpenTelemetryConfig +from .middleware import OpenTelemetryInstrumentationMiddleware + +__all__ = ("OpenTelemetryConfig", "OpenTelemetryInstrumentationMiddleware") diff --git a/venv/lib/python3.11/site-packages/litestar/contrib/opentelemetry/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/litestar/contrib/opentelemetry/__pycache__/__init__.cpython-311.pyc Binary files differnew file mode 100644 index 0000000..799a915 --- /dev/null +++ b/venv/lib/python3.11/site-packages/litestar/contrib/opentelemetry/__pycache__/__init__.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/litestar/contrib/opentelemetry/__pycache__/_utils.cpython-311.pyc b/venv/lib/python3.11/site-packages/litestar/contrib/opentelemetry/__pycache__/_utils.cpython-311.pyc Binary files differnew file mode 100644 index 0000000..c401f9c --- /dev/null +++ b/venv/lib/python3.11/site-packages/litestar/contrib/opentelemetry/__pycache__/_utils.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/litestar/contrib/opentelemetry/__pycache__/config.cpython-311.pyc b/venv/lib/python3.11/site-packages/litestar/contrib/opentelemetry/__pycache__/config.cpython-311.pyc Binary files differnew file mode 100644 index 0000000..b41bc7e --- /dev/null +++ b/venv/lib/python3.11/site-packages/litestar/contrib/opentelemetry/__pycache__/config.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/litestar/contrib/opentelemetry/__pycache__/middleware.cpython-311.pyc b/venv/lib/python3.11/site-packages/litestar/contrib/opentelemetry/__pycache__/middleware.cpython-311.pyc Binary files differnew file mode 100644 index 0000000..291b510 --- /dev/null +++ b/venv/lib/python3.11/site-packages/litestar/contrib/opentelemetry/__pycache__/middleware.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/litestar/contrib/opentelemetry/_utils.py b/venv/lib/python3.11/site-packages/litestar/contrib/opentelemetry/_utils.py new file mode 100644 index 0000000..0ba7cb9 --- /dev/null +++ b/venv/lib/python3.11/site-packages/litestar/contrib/opentelemetry/_utils.py @@ -0,0 +1,31 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING, Any + +from litestar.exceptions import MissingDependencyException + +__all__ = ("get_route_details_from_scope",) + + +try: + import opentelemetry # noqa: F401 +except ImportError as e: + raise MissingDependencyException("opentelemetry") from e + +from opentelemetry.semconv.trace import SpanAttributes + +if TYPE_CHECKING: + from litestar.types import Scope + + +def get_route_details_from_scope(scope: Scope) -> tuple[str, dict[Any, str]]: + """Retrieve the span name and attributes from the ASGI scope. + + Args: + scope: The ASGI scope instance. + + Returns: + A tuple of the span name and a dict of attrs. + """ + route_handler_fn_name = scope["route_handler"].handler_name + return route_handler_fn_name, {SpanAttributes.HTTP_ROUTE: route_handler_fn_name} diff --git a/venv/lib/python3.11/site-packages/litestar/contrib/opentelemetry/config.py b/venv/lib/python3.11/site-packages/litestar/contrib/opentelemetry/config.py new file mode 100644 index 0000000..c0cce8a --- /dev/null +++ b/venv/lib/python3.11/site-packages/litestar/contrib/opentelemetry/config.py @@ -0,0 +1,102 @@ +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import TYPE_CHECKING, Any, Callable + +from litestar.contrib.opentelemetry._utils import get_route_details_from_scope +from litestar.contrib.opentelemetry.middleware import ( + OpenTelemetryInstrumentationMiddleware, +) +from litestar.exceptions import MissingDependencyException +from litestar.middleware.base import DefineMiddleware + +__all__ = ("OpenTelemetryConfig",) + + +try: + import opentelemetry # noqa: F401 +except ImportError as e: + raise MissingDependencyException("opentelemetry") from e + + +from opentelemetry.trace import Span, TracerProvider # pyright: ignore + +if TYPE_CHECKING: + from opentelemetry.metrics import Meter, MeterProvider + + from litestar.types import Scope, Scopes + +OpenTelemetryHookHandler = Callable[[Span, dict], None] + + +@dataclass +class OpenTelemetryConfig: + """Configuration class for the OpenTelemetry middleware. + + Consult the [OpenTelemetry ASGI documentation](https://opentelemetry-python-contrib.readthedocs.io/en/latest/instrumentation/asgi/asgi.html) for more info about the configuration options. + """ + + scope_span_details_extractor: Callable[[Scope], tuple[str, dict[str, Any]]] = field( + default=get_route_details_from_scope + ) + """Callback which should return a string and a tuple, representing the desired default span name and a dictionary + with any additional span attributes to set. + """ + server_request_hook_handler: OpenTelemetryHookHandler | None = field(default=None) + """Optional callback which is called with the server span and ASGI scope object for every incoming request.""" + client_request_hook_handler: OpenTelemetryHookHandler | None = field(default=None) + """Optional callback which is called with the internal span and an ASGI scope which is sent as a dictionary for when + the method receive is called. + """ + client_response_hook_handler: OpenTelemetryHookHandler | None = field(default=None) + """Optional callback which is called with the internal span and an ASGI event which is sent as a dictionary for when + the method send is called. + """ + meter_provider: MeterProvider | None = field(default=None) + """Optional meter provider to use. + + If omitted the current globally configured one is used. + """ + tracer_provider: TracerProvider | None = field(default=None) + """Optional tracer provider to use. + + If omitted the current globally configured one is used. + """ + meter: Meter | None = field(default=None) + """Optional meter to use. + + If omitted the provided meter provider or the global one will be used. + """ + exclude: str | list[str] | None = field(default=None) + """A pattern or list of patterns to skip in the Allowed Hosts middleware.""" + exclude_opt_key: str | None = field(default=None) + """An identifier to use on routes to disable hosts check for a particular route.""" + exclude_urls_env_key: str = "LITESTAR" + """Key to use when checking whether a list of excluded urls is passed via ENV. + + OpenTelemetry supports excluding urls by passing an env in the format '{exclude_urls_env_key}_EXCLUDED_URLS'. With + the default being ``LITESTAR_EXCLUDED_URLS``. + """ + scopes: Scopes | None = field(default=None) + """ASGI scopes processed by the middleware, if None both ``http`` and ``websocket`` will be processed.""" + middleware_class: type[OpenTelemetryInstrumentationMiddleware] = field( + default=OpenTelemetryInstrumentationMiddleware + ) + """The middleware class to use. + + Should be a subclass of OpenTelemetry + InstrumentationMiddleware][litestar.contrib.opentelemetry.OpenTelemetryInstrumentationMiddleware]. + """ + + @property + def middleware(self) -> DefineMiddleware: + """Create an instance of :class:`DefineMiddleware <litestar.middleware.base.DefineMiddleware>` that wraps with. + + [OpenTelemetry + InstrumentationMiddleware][litestar.contrib.opentelemetry.OpenTelemetryInstrumentationMiddleware] or a subclass + of this middleware. + + Returns: + An instance of ``DefineMiddleware``. + """ + return DefineMiddleware(self.middleware_class, config=self) diff --git a/venv/lib/python3.11/site-packages/litestar/contrib/opentelemetry/middleware.py b/venv/lib/python3.11/site-packages/litestar/contrib/opentelemetry/middleware.py new file mode 100644 index 0000000..762bae9 --- /dev/null +++ b/venv/lib/python3.11/site-packages/litestar/contrib/opentelemetry/middleware.py @@ -0,0 +1,60 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +from litestar.exceptions import MissingDependencyException +from litestar.middleware.base import AbstractMiddleware + +__all__ = ("OpenTelemetryInstrumentationMiddleware",) + + +try: + import opentelemetry # noqa: F401 +except ImportError as e: + raise MissingDependencyException("opentelemetry") from e + +from opentelemetry.instrumentation.asgi import OpenTelemetryMiddleware +from opentelemetry.util.http import get_excluded_urls + +if TYPE_CHECKING: + from litestar.contrib.opentelemetry import OpenTelemetryConfig + from litestar.types import ASGIApp, Receive, Scope, Send + + +class OpenTelemetryInstrumentationMiddleware(AbstractMiddleware): + """OpenTelemetry Middleware.""" + + __slots__ = ("open_telemetry_middleware",) + + def __init__(self, app: ASGIApp, config: OpenTelemetryConfig) -> None: + """Middleware that adds OpenTelemetry instrumentation to the application. + + Args: + app: The ``next`` ASGI app to call. + config: An instance of :class:`OpenTelemetryConfig <.contrib.opentelemetry.OpenTelemetryConfig>` + """ + super().__init__(app=app, scopes=config.scopes, exclude=config.exclude, exclude_opt_key=config.exclude_opt_key) + self.open_telemetry_middleware = OpenTelemetryMiddleware( + app=app, + client_request_hook=config.client_request_hook_handler, + client_response_hook=config.client_response_hook_handler, + default_span_details=config.scope_span_details_extractor, + excluded_urls=get_excluded_urls(config.exclude_urls_env_key), + meter=config.meter, + meter_provider=config.meter_provider, + server_request_hook=config.server_request_hook_handler, + tracer_provider=config.tracer_provider, + ) + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + """ASGI callable. + + Args: + scope: The ASGI connection scope. + receive: The ASGI receive function. + send: The ASGI send function. + + Returns: + None + """ + await self.open_telemetry_middleware(scope, receive, send) # type: ignore[arg-type] # pyright: ignore[reportGeneralTypeIssues] |