Skip to content

Commit 2d11517

Browse files
committed
starlette/fastapi: fix error on host-based routing
Fix #3506
1 parent 032d6c6 commit 2d11517

File tree

4 files changed

+53
-3
lines changed

4 files changed

+53
-3
lines changed

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,11 @@ def _get_route_details(scope):
457457
for starlette_route in app.routes:
458458
match, _ = starlette_route.matches(scope)
459459
if match == Match.FULL:
460-
route = starlette_route.path
460+
try:
461+
route = starlette_route.path
462+
except AttributeError:
463+
# routes added via host routing won't have a path attribute
464+
route = scope.get("path")
461465
break
462466
if match == Match.PARTIAL:
463467
route = starlette_route.path

instrumentation/opentelemetry-instrumentation-fastapi/tests/test_fastapi_instrumentation.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ async def _():
230230
raise UnhandledException("This is an unhandled exception")
231231

232232
app.mount("/sub", app=sub_app)
233+
app.host("testserver2", sub_app)
233234

234235
return app
235236

@@ -306,6 +307,26 @@ def test_sub_app_fastapi_call(self):
306307
span.attributes[HTTP_URL],
307308
)
308309

310+
def test_host_fastapi_call(self):
311+
client = TestClient(self._app, base_url="https://testserver2")
312+
client.get("/")
313+
spans = self.memory_exporter.get_finished_spans()
314+
315+
spans_with_http_attributes = [
316+
span
317+
for span in spans
318+
if (HTTP_URL in span.attributes or HTTP_TARGET in span.attributes)
319+
]
320+
321+
self.assertEqual(1, len(spans_with_http_attributes))
322+
323+
for span in spans_with_http_attributes:
324+
self.assertEqual("/", span.attributes[HTTP_TARGET])
325+
self.assertEqual(
326+
"https://testserver2:443/",
327+
span.attributes[HTTP_URL],
328+
)
329+
309330

310331
class TestBaseAutoFastAPI(TestBaseFastAPI):
311332
@classmethod

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,11 @@ def _get_route_details(scope: dict[str, Any]) -> str | None:
354354
for starlette_route in app.routes:
355355
match, _ = starlette_route.matches(scope)
356356
if match == Match.FULL:
357-
route = starlette_route.path
357+
try:
358+
route = starlette_route.path
359+
except AttributeError:
360+
# routes added via host routing won't have a path attribute
361+
route = scope.get("path")
358362
break
359363
if match == Match.PARTIAL:
360364
route = starlette_route.path

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

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
from starlette import applications
2020
from starlette.responses import PlainTextResponse
21-
from starlette.routing import Mount, Route
21+
from starlette.routing import Host, Mount, Route
2222
from starlette.testclient import TestClient
2323
from starlette.websockets import WebSocket
2424

@@ -140,6 +140,26 @@ def test_sub_app_starlette_call(self):
140140
span.attributes[HTTP_URL],
141141
)
142142

143+
def test_host_starlette_call(self):
144+
client = TestClient(self._app, base_url="http://testserver2")
145+
client.get("/")
146+
spans = self.memory_exporter.get_finished_spans()
147+
148+
spans_with_http_attributes = [
149+
span
150+
for span in spans
151+
if (HTTP_URL in span.attributes or HTTP_TARGET in span.attributes)
152+
]
153+
154+
self.assertEqual(1, len(spans_with_http_attributes))
155+
156+
for span in spans_with_http_attributes:
157+
self.assertEqual("/", span.attributes[HTTP_TARGET])
158+
self.assertEqual(
159+
"https://testserver2:443/",
160+
span.attributes[HTTP_URL],
161+
)
162+
143163
def test_starlette_route_attribute_added(self):
144164
"""Ensure that starlette routes are used as the span name."""
145165
self._client.get("/user/123")
@@ -294,6 +314,7 @@ def sub_home(_):
294314
Route("/user/{username}", home),
295315
Route("/healthzz", health),
296316
Mount("/sub", app=sub_app),
317+
Host("testserver2", sub_app),
297318
],
298319
)
299320

0 commit comments

Comments
 (0)