From 5578f63db56fe33aafa6b3df5f6c217d6dd5d207 Mon Sep 17 00:00:00 2001 From: Artur Shiriev Date: Sat, 2 May 2026 12:25:21 +0300 Subject: [PATCH] fix: cache OpenTelemetryMiddleware in litestar instrumentation LitestarOpenTelemetryInstrumentationMiddleware.handle constructed a fresh OpenTelemetryMiddleware on every request. Cache it per next_app so tracers and metric instruments are allocated once. --- .../bootstrappers/litestar_bootstrapper.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/lite_bootstrap/bootstrappers/litestar_bootstrapper.py b/lite_bootstrap/bootstrappers/litestar_bootstrapper.py index 18334a0..ad1cc5a 100644 --- a/lite_bootstrap/bootstrappers/litestar_bootstrapper.py +++ b/lite_bootstrap/bootstrappers/litestar_bootstrapper.py @@ -76,6 +76,7 @@ class LitestarOpenTelemetryInstrumentationMiddleware(ASGIMiddleware): def __init__(self, tracer_provider: "TracerProvider", excluded_urls: set[str]) -> None: self._tracer_provider = tracer_provider self._excluded_urls = ",".join(excluded_urls) + self._otel_apps: dict[int, ASGIApp] = {} async def handle( self, @@ -84,12 +85,16 @@ async def handle( send: "Send", next_app: "ASGIApp", ) -> None: - await OpenTelemetryMiddleware( - app=next_app, - default_span_details=build_litestar_route_details_from_scope, - excluded_urls=self._excluded_urls, - tracer_provider=self._tracer_provider, - )(scope, receive, send) # ty: ignore[invalid-argument-type] + otel_app = self._otel_apps.get(id(next_app)) + if otel_app is None: + otel_app = OpenTelemetryMiddleware( + app=next_app, + default_span_details=build_litestar_route_details_from_scope, + excluded_urls=self._excluded_urls, + tracer_provider=self._tracer_provider, + ) + self._otel_apps[id(next_app)] = otel_app # ty: ignore[invalid-assignment] + await otel_app(scope, receive, send) # ty: ignore[invalid-argument-type] @dataclasses.dataclass(kw_only=True, slots=True, frozen=True)