feat(telemetry): normalize path (#1739)

# What does this PR do?
This will prevent 'operations' from being flooded 
<img width="401" alt="image"
src="https://github.com/user-attachments/assets/c95e0eeb-4a10-4003-88df-9bb6d0a548cd"
/>


Before
<img width="1049" alt="image"
src="https://github.com/user-attachments/assets/157fb614-e007-4cb3-a571-226e50525bfa"
/>


## Test Plan
After
<img width="811" alt="image"
src="https://github.com/user-attachments/assets/b2b10344-1d73-44e5-abee-a9f039090963"
/>
This commit is contained in:
ehhuang 2025-03-21 10:17:43 -07:00 committed by GitHub
parent 636d97207f
commit f76550ce4e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -228,13 +228,51 @@ class TracingMiddleware:
async def __call__(self, scope, receive, send):
if scope.get("type") == "lifespan":
return await self.app(scope, receive, send)
path = scope.get("path", "")
await start_trace(path, {"__location__": "server"})
# Try to match the path to a route template
route_template = self._match_path(path)
# Use the matched template or original path
trace_path = route_template or path
await start_trace(trace_path, {"__location__": "server", "raw_path": path})
try:
return await self.app(scope, receive, send)
finally:
await end_trace()
def _match_path(self, path):
"""Match a path to a route template using simple segment matching."""
path_segments = path.split("/")
for route in self.app.app.routes:
if not hasattr(route, "path"):
continue
route_path = route.path
route_segments = route_path.split("/")
# Skip if number of segments doesn't match
if len(path_segments) != len(route_segments):
continue
matches = True
for path_seg, route_seg in zip(path_segments, route_segments, strict=True):
# If route segment is a parameter (contains {...}), it matches anything
if route_seg.startswith("{") and route_seg.endswith("}"):
continue
# Otherwise, segments must match exactly
elif path_seg != route_seg:
matches = False
break
if matches:
return route_path
return None
class ClientVersionMiddleware:
def __init__(self, app):