Skip to content

fix(logging): make access-log http.route resolution framework-robust#16

Merged
sidxz merged 1 commit into
mainfrom
fix/access-log-route-template
Jun 20, 2026
Merged

fix(logging): make access-log http.route resolution framework-robust#16
sidxz merged 1 commit into
mainfrom
fix/access-log-route-template

Conversation

@sidxz

@sidxz sidxz commented Jun 18, 2026

Copy link
Copy Markdown
Owner

Problem

AccessLogMiddleware._route_template read the matched route's .path. Newer Starlette
(1.x) renamed that to .path_format (.path is None), so every request logged
http.route="__unmatched__"
— silently defeating per-route observability (latency
dashboards, cardinality baselining, the documented http.access contract).

This is already affecting shipped 0.13.0: the service Dockerfile resolves deps from
pyproject.toml (it never COPYs uv.lock), so the container installs the latest
compatible starlette (1.x), not the locked 0.52.1. make start (which honors the lock)
masked it locally.

Fix

Prefer scope["route"] (the router records it) and read path_formatpath, with a
fallback that maps scope["endpoint"] back to its route. Robust across the framework's
routing reworks.

Verification

Real-app TestClient capture on both starlette 0.52.1 and 1.3.1:

GET /auth/providers 200 -> /auth/providers
POST /authz/resolve 401 -> /authz/resolve
GET /admin/activity 401 -> /admin/activity
GET /nope          404 -> __unmatched__

Plus a regression test pinning the path_format/path robustness; service suite 227 ✓.

Follow-ups (separate)

🤖 Generated with Claude Code

AccessLogMiddleware._route_template read the matched route's `.path`, which newer
Starlette (1.x — what the service container actually resolves at build time)
renamed to `.path_format` (`.path` is None) — so EVERY request logged
http.route="__unmatched__", silently defeating per-route observability. The unit
test missed it: its toy app uses a small middleware stack and directly-added
routes where `.path` is still set.

Prefer scope["route"] (the router records it) and read path_format-or-path, with
a fallback that maps scope["endpoint"] back to its route. Verified resolving real
templates (/auth/providers, /authz/resolve, /admin/activity; 404 -> __unmatched__)
on BOTH starlette 0.52 and 1.3. Adds a regression test pinning path_format/path.

Why now: the shipped image installs latest-within-pyproject (the Dockerfile
resolves from pyproject, not the frozen lock), so 0.13.0's container already runs
starlette 1.x — the prod access-log is broken until this lands.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@sidxz sidxz merged commit 95cac79 into main Jun 20, 2026
5 checks passed
@sidxz sidxz deleted the fix/access-log-route-template branch June 20, 2026 13:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant