-
Notifications
You must be signed in to change notification settings - Fork 806
Use canonical name for aiohttp request span name #3896
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
1ba9a1c to
8689cfc
Compare
bisgaard-itis
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. Thanks a lot for the effort! 👍🏻
| for request_path, span in zip( | ||
| example_paths, memory_exporter.get_finished_spans() | ||
| ): | ||
| assert url == span.name |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍🏻
| a tuple of the span name, and any attributes to attach to the span. | ||
| """ | ||
| span_name = request.path.strip() or f"HTTP {request.method}" | ||
| if request.match_info and request.match_info.route.resource: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is match_info.route guaranteed to be not None when match_info is not None?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thank you for the good point. i think this can be the proof: https://github.com/aio-libs/aiohttp/blob/v3.13.1/aiohttp/web_urldispatcher.py#L271
(in fact, even match_info can't be None: https://github.com/aio-libs/aiohttp/blob/v3.13.1/aiohttp/web_request.py#L890 but it may raise issues with type hints)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not super familiar with aiohttp, but it could we be extra careful and wrap this with a try-except AttributeError? So it's like _get_view_func below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i am pretty sure that the attributes always exist: https://github.com/aio-libs/aiohttp/blob/v3.5.0/aiohttp/web_request.py#L704 https://github.com/aio-libs/aiohttp/blob/v3.5.0/aiohttp/web_urldispatcher.py#L161 (at least since v3.5.0)
but we definitely can add this "extra-safe" layer. i am just not sure yet what should the name be in case of AttributeError - the default one from request.path or some sentinel because "we-found-smth-unexpected"... having thought about it for a while i decided that the first option is better. let me know if you have any other ideas.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in fact, there's another possibility of "high cardinality abuse": https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3896/files#diff-682c3e961f134b947f243e707c7a75856ea5640e0dfb8f32dad7ffd1b3fa8c9eR145
every non existent name is a span name by itself. so, you can generate an endless amount of 404 and each of them will be a different span. this logic should be (should it?) fixed in a separate PR, because i can't decide right on the spot what shall we do with 404 span names. should they all be "GET <Not Found>" if there's no match_info (i think so, and only get the path from the span attributes), or some users rely on the existing behavior and collect an "inventory" of such calls using span names? i don't know.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good questions, hmm. This part of the semconv says
HTTP span names SHOULD be
{method} {target}if there is a (low-cardinality) target available. If there is no (low-cardinality){target}available, HTTP span names SHOULD be{method}.
I'm guessing cardinality of request.path.strip() can depend on the app but does have the potential to be high. What do you think of something like below, where we prefer target (path) as canonical > None? If we stop relying request.path.strip() entirely, maybe this would address the endless-404s concern, though it might be a small breaking change to some users:
try:
resource = request.match_info.route.resource
if resource:
path = resource.canonical
except AttributeError:
path = ""
if path:
return f"{request.method} {path}"
else:
return f"{request.method}"There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, i think it will be better. i just modified it a bit to silent a type checker.
...-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py
Outdated
Show resolved
Hide resolved
c05f041 to
3bb8b84
Compare
Co-authored-by: Tammy Baylis <96076570+tammy-baylis-swi@users.noreply.github.com>
5f4116a to
32ccac9
Compare
Description
Current implementation doesn't use canonical attribute of a
Resource, which leads to the situation when generated spans all have unique names. It creates high cardinality of spans. Other frameworks that use path params create spans with "canonical" paths in names (e.g. fastapi [1] )Type of change
How Has This Been Tested?
add a new unit test:
test_url_params_instrumentationDoes This PR Require a Core Repo Change?
Checklist:
See contributing.md for styleguide, changelog guidelines, and more.