Skip to content

Commit 3aebb34

Browse files
committed
opentelemetry-instrumentation-starlette: fix memory leak and double middleware
1 parent 6c89a56 commit 3aebb34

File tree

2 files changed

+14
-8
lines changed

2 files changed

+14
-8
lines changed

instrumentation/opentelemetry-instrumentation-starlette/src/opentelemetry/instrumentation/starlette/__init__.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ def client_response_hook(span: Span, scope: dict[str, Any], message: dict[str, A
177177
from __future__ import annotations
178178

179179
from typing import TYPE_CHECKING, Any, Collection, cast
180+
from weakref import WeakSet
180181

181182
from starlette import applications
182183
from starlette.routing import Match
@@ -239,7 +240,7 @@ def instrument_app(
239240
meter_provider,
240241
schema_url="https://opentelemetry.io/schemas/1.11.0",
241242
)
242-
if not getattr(app, "is_instrumented_by_opentelemetry", False):
243+
if not getattr(app, "_is_instrumented_by_opentelemetry", False):
243244
app.add_middleware(
244245
OpenTelemetryMiddleware,
245246
excluded_urls=_excluded_urls,
@@ -251,11 +252,10 @@ def instrument_app(
251252
tracer=tracer,
252253
meter=meter,
253254
)
254-
app.is_instrumented_by_opentelemetry = True
255+
app._is_instrumented_by_opentelemetry = True
255256

256257
# adding apps to set for uninstrumenting
257-
if app not in _InstrumentedStarlette._instrumented_starlette_apps:
258-
_InstrumentedStarlette._instrumented_starlette_apps.add(app)
258+
_InstrumentedStarlette._instrumented_starlette_apps.add(app)
259259

260260
@staticmethod
261261
def uninstrument_app(app: applications.Starlette):
@@ -300,7 +300,7 @@ class _InstrumentedStarlette(applications.Starlette):
300300
_server_request_hook: ServerRequestHook = None
301301
_client_request_hook: ClientRequestHook = None
302302
_client_response_hook: ClientResponseHook = None
303-
_instrumented_starlette_apps: set[applications.Starlette] = set()
303+
_instrumented_starlette_apps: WeakSet[applications.Starlette] = WeakSet()
304304

305305
def __init__(self, *args: Any, **kwargs: Any):
306306
super().__init__(*args, **kwargs)
@@ -331,9 +331,6 @@ def __init__(self, *args: Any, **kwargs: Any):
331331
# adding apps to set for uninstrumenting
332332
_InstrumentedStarlette._instrumented_starlette_apps.add(self)
333333

334-
def __del__(self):
335-
_InstrumentedStarlette._instrumented_starlette_apps.discard(self)
336-
337334

338335
def _get_route_details(scope: dict[str, Any]) -> str | None:
339336
"""

instrumentation/opentelemetry-instrumentation-starlette/tests/test_starlette_instrumentation.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,15 @@ def test_no_op_tracer_provider(self):
413413
spans = self.memory_exporter.get_finished_spans()
414414
self.assertEqual(len(spans), 0)
415415

416+
def test_manual_instrument_is_noop(self):
417+
app = self._create_starlette_app()
418+
self._instrumentor.instrument_app(app)
419+
self.assertEqual(len(app.user_middleware), 1)
420+
client = TestClient(app)
421+
client.get("/foobar")
422+
spans = self.memory_exporter.get_finished_spans()
423+
self.assertEqual(len(spans), 3)
424+
416425
def test_sub_app_starlette_call(self):
417426
"""
418427
!!! Attention: we need to override this testcase for the auto-instrumented variant

0 commit comments

Comments
 (0)