Skip to content

Commit 4db9772

Browse files
rads-1996emdnetoxrmx
authored
Fix for FASTAPI unable to record AppService URL (Issue #3654) (#3670)
* Fix for FASTAPI unable to record AppService URL * Fixed tests and pylint errors * Fixed ruff format * Updated CHANGELOG * Updated CHANGELOG * Addressed feedback * Checking CI runs * Fix ruff and spellcheck errors * Fix pytest * Update CHANGELOG.md * Update CHANGELOG.md * Update instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/__init__.py * Fix ruff * Fix ruff * Updated CHANGELOG --------- Co-authored-by: Emídio Neto <[email protected]> Co-authored-by: Riccardo Magliocchetti <[email protected]>
1 parent b2c3c4e commit 4db9772

File tree

5 files changed

+369
-19
lines changed

5 files changed

+369
-19
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2929
([#3507](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3507))
3030
- Fix documentation order of sections and headers for Django, Flask, MySQL, mysqlclient, psycopg, psycopg2, pymysql, sqlalchemy instrumentations.
3131
([#3719](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3719))
32+
- `opentelemetry-instrumentation-asgi` Fixed an issue where FastAPI reports IP instead of URL.
33+
([#3670](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3670))
3234
- `opentelemetry-instrumentation-httpx`: fix missing metric response attributes when tracing is disabled
3335
([#3615](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3615))
3436
- `opentelemetry-instrumentation-fastapi`: Don't pass bounded server_request_hook when using `FastAPIInstrumentor.instrument()`

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -445,15 +445,28 @@ def get_host_port_url_tuple(scope):
445445
"""Returns (host, port, full_url) tuple."""
446446
server = scope.get("server") or ["0.0.0.0", 80]
447447
port = server[1]
448+
449+
host_header = asgi_getter.get(scope, "host")
450+
if host_header:
451+
host_value = host_header[0]
452+
# Ensure host_value is a string, not bytes
453+
if isinstance(host_value, bytes):
454+
host_value = _decode_header_item(host_value)
455+
456+
url_host = host_value
457+
458+
else:
459+
url_host = server[0] + (":" + str(port) if str(port) != "80" else "")
448460
server_host = server[0] + (":" + str(port) if str(port) != "80" else "")
461+
449462
# using the scope path is enough, see:
450463
# - https://asgi.readthedocs.io/en/latest/specs/www.html#http-connection-scope (see: root_path and path)
451464
# - https://asgi.readthedocs.io/en/latest/specs/www.html#wsgi-compatibility (see: PATH_INFO)
452465
# PATH_INFO can be derived by stripping root_path from path
453466
# -> that means that the path should contain the root_path already, so prefixing it again is not necessary
454467
# - https://wsgi.readthedocs.io/en/latest/definitions.html#envvar-PATH_INFO
455468
full_path = scope.get("path", "")
456-
http_url = scope.get("scheme", "http") + "://" + server_host + full_path
469+
http_url = scope.get("scheme", "http") + "://" + url_host + full_path
457470
return server_host, port, http_url
458471

459472

instrumentation/opentelemetry-instrumentation-asgi/tests/test_asgi_middleware.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -780,7 +780,10 @@ async def test_host_header(self):
780780

781781
def update_expected_server(expected):
782782
expected[3]["attributes"].update(
783-
{SpanAttributes.HTTP_SERVER_NAME: hostname.decode("utf8")}
783+
{
784+
SpanAttributes.HTTP_SERVER_NAME: hostname.decode("utf8"),
785+
SpanAttributes.HTTP_URL: f"http://{hostname.decode('utf8')}/",
786+
}
784787
)
785788
return expected
786789

@@ -797,7 +800,10 @@ async def test_host_header_both_semconv(self):
797800

798801
def update_expected_server(expected):
799802
expected[3]["attributes"].update(
800-
{SpanAttributes.HTTP_SERVER_NAME: hostname.decode("utf8")}
803+
{
804+
SpanAttributes.HTTP_SERVER_NAME: hostname.decode("utf8"),
805+
SpanAttributes.HTTP_URL: f"http://{hostname.decode('utf8')}/",
806+
}
801807
)
802808
return expected
803809

@@ -1728,7 +1734,7 @@ def test_request_attributes(self):
17281734
SpanAttributes.HTTP_METHOD: "GET",
17291735
SpanAttributes.HTTP_HOST: "127.0.0.1",
17301736
SpanAttributes.HTTP_TARGET: "/",
1731-
SpanAttributes.HTTP_URL: "http://127.0.0.1/?foo=bar",
1737+
SpanAttributes.HTTP_URL: "http://test/?foo=bar",
17321738
SpanAttributes.NET_HOST_PORT: 80,
17331739
SpanAttributes.HTTP_SCHEME: "http",
17341740
SpanAttributes.HTTP_SERVER_NAME: "test",
@@ -1781,7 +1787,7 @@ def test_request_attributes_both_semconv(self):
17811787
SpanAttributes.HTTP_METHOD: "GET",
17821788
SpanAttributes.HTTP_HOST: "127.0.0.1",
17831789
SpanAttributes.HTTP_TARGET: "/",
1784-
SpanAttributes.HTTP_URL: "http://127.0.0.1/?foo=bar",
1790+
SpanAttributes.HTTP_URL: "http://test/?foo=bar",
17851791
SpanAttributes.NET_HOST_PORT: 80,
17861792
SpanAttributes.HTTP_SCHEME: "http",
17871793
SpanAttributes.HTTP_SERVER_NAME: "test",

instrumentation/opentelemetry-instrumentation-django/tests/test_middleware_asgi.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ async def test_templated_route_get(self):
174174
self.assertEqual(span.attributes[SpanAttributes.HTTP_METHOD], "GET")
175175
self.assertEqual(
176176
span.attributes[SpanAttributes.HTTP_URL],
177-
"http://127.0.0.1/route/2020/template/",
177+
"http://testserver/route/2020/template/",
178178
)
179179
self.assertEqual(
180180
span.attributes[SpanAttributes.HTTP_ROUTE],
@@ -219,7 +219,7 @@ async def test_templated_route_get_both_semconv(self):
219219
self.assertEqual(span.attributes[SpanAttributes.HTTP_METHOD], "GET")
220220
self.assertEqual(
221221
span.attributes[SpanAttributes.HTTP_URL],
222-
"http://127.0.0.1/route/2020/template/",
222+
"http://testserver/route/2020/template/",
223223
)
224224
self.assertEqual(span.attributes[SpanAttributes.HTTP_SCHEME], "http")
225225
self.assertEqual(span.attributes[SpanAttributes.HTTP_STATUS_CODE], 200)
@@ -248,7 +248,7 @@ async def test_traced_get(self):
248248
self.assertEqual(span.attributes[SpanAttributes.HTTP_METHOD], "GET")
249249
self.assertEqual(
250250
span.attributes[SpanAttributes.HTTP_URL],
251-
"http://127.0.0.1/traced/",
251+
"http://testserver/traced/",
252252
)
253253
self.assertEqual(
254254
span.attributes[SpanAttributes.HTTP_ROUTE], "^traced/"
@@ -289,7 +289,7 @@ async def test_traced_get_both_semconv(self):
289289
self.assertEqual(span.attributes[SpanAttributes.HTTP_METHOD], "GET")
290290
self.assertEqual(
291291
span.attributes[SpanAttributes.HTTP_URL],
292-
"http://127.0.0.1/traced/",
292+
"http://testserver/traced/",
293293
)
294294
self.assertEqual(span.attributes[SpanAttributes.HTTP_SCHEME], "http")
295295
self.assertEqual(span.attributes[SpanAttributes.HTTP_STATUS_CODE], 200)
@@ -328,7 +328,7 @@ async def test_traced_post(self):
328328
self.assertEqual(span.attributes[SpanAttributes.HTTP_METHOD], "POST")
329329
self.assertEqual(
330330
span.attributes[SpanAttributes.HTTP_URL],
331-
"http://127.0.0.1/traced/",
331+
"http://testserver/traced/",
332332
)
333333
self.assertEqual(
334334
span.attributes[SpanAttributes.HTTP_ROUTE], "^traced/"
@@ -369,7 +369,7 @@ async def test_traced_post_both_semconv(self):
369369
self.assertEqual(span.attributes[SpanAttributes.HTTP_METHOD], "POST")
370370
self.assertEqual(
371371
span.attributes[SpanAttributes.HTTP_URL],
372-
"http://127.0.0.1/traced/",
372+
"http://testserver/traced/",
373373
)
374374
self.assertEqual(span.attributes[SpanAttributes.HTTP_SCHEME], "http")
375375
self.assertEqual(span.attributes[SpanAttributes.HTTP_STATUS_CODE], 200)
@@ -396,7 +396,7 @@ async def test_error(self):
396396
self.assertEqual(span.attributes[SpanAttributes.HTTP_METHOD], "GET")
397397
self.assertEqual(
398398
span.attributes[SpanAttributes.HTTP_URL],
399-
"http://127.0.0.1/error/",
399+
"http://testserver/error/",
400400
)
401401
self.assertEqual(span.attributes[SpanAttributes.HTTP_ROUTE], "^error/")
402402
self.assertEqual(span.attributes[SpanAttributes.HTTP_SCHEME], "http")
@@ -450,7 +450,7 @@ async def test_error_both_semconv(self):
450450
self.assertEqual(span.attributes[SpanAttributes.HTTP_METHOD], "GET")
451451
self.assertEqual(
452452
span.attributes[SpanAttributes.HTTP_URL],
453-
"http://127.0.0.1/error/",
453+
"http://testserver/error/",
454454
)
455455
self.assertEqual(span.attributes[SpanAttributes.HTTP_ROUTE], "^error/")
456456
self.assertEqual(span.attributes[SpanAttributes.HTTP_SCHEME], "http")

0 commit comments

Comments
 (0)