Skip to content

fix: anchor litestar trace-exclusion patterns to the normalized path - #250

Merged
lesnik512 merged 1 commit into
mainfrom
fix/248-litestar-trailing-slash-exclusion
Sep 20, 2026
Merged

lesnik512 merged 1 commit into
mainfrom
fix/248-litestar-trailing-slash-exclusion

Conversation

@lesnik512

Copy link
Copy Markdown
Member

Closes #248.

The defect

opentelemetry_generate_health_check_spans=False silently did nothing on Litestar. Litestar
normalizes the trailing slash out of scope["path"], so OpenTelemetryMiddleware built
http://host/custom-health while the excluded entry was /custom-health/. ExcludeList
regex-searches, missed, and the health check was traced anyway.

The default health_checks_path is /health/, so this is the default configuration. FastAPI is
unaffected because Starlette does not normalize the slash away.

Confirmed before the fix with an in-memory exporter: 3 spans for /custom-health/ and 3 for
/custom-metrics/, each carrying http.url = http://testserver.local/custom-health.

The fix

Stripping the slash alone would have been wrong. ExcludeList.url_disabled is
bool(search(regex, url)) over a | alternation, so entries are unanchored substrings, and a bare
/custom-health would have started excluding /custom-healthy from tracing instead. So the derived
paths are rendered as anchored patterns:

rf"^\w+://[^/]*{re.escape(path.rstrip('/'))}(?:/|$)"

[^/]* cannot cross a slash, which pins the path to the start of the URL's path component, so
/api/custom-health does not match either. (?:/|$) admits sub-paths but not the lookalike. The
middleware's URL carries no query string (get_host_port_url_tuple builds scheme://host +
scope["path"]), so $ is safe.

Caller-supplied entries pass through verbatim

opentelemetry_excluded_urls entries are OpenTelemetry regexes, not paths. re.escape would have
destroyed an entry like client/.*/info, and anchoring it to the scheme and host would have broken
it a second way — on Litestar only, while FastAPI kept honoring it. They are therefore left
untouched, with a test pinning that.

That required separating the two kinds of entry, so _build_excluded_urls now composes
_build_infrastructure_excluded_paths() with the caller's list. FastAPI and FastStream consume the
merged set exactly as before. The exclusion policy — which paths, and the getattr sibling reads —
still lives in one method, so ADR-0002 holds; only the rendering differs per framework.

Scope

Litestar only, as the issue specified. FastAPI has the mirror-image defect from the same unanchored
search (prometheus_metrics_path="/metrics" also excludes /metrics-internal), but that is a false
exclusion rather than a false trace, nobody has hit it, and fixing it would change released behaviour
on a framework that currently works.

Verification

Span counts through an in-memory exporter, not url_disabled on a hand-written URL — the test added
in #247 asserted url_disabled("http://test/custom-health/"), a URL form the middleware never
receives, and passed while the behaviour it described was false. That stale comment is removed here.

  • test_litestar_otel_excludes_infrastructure_paths_normalized_by_litestar — health and metrics
    paths emit no spans; /custom-healthy still does.
  • test_litestar_otel_keeps_caller_supplied_excluded_urls_as_regexes/items/\d+$ still excludes
    /items/42, which only passes if the regex survived unescaped.

Full suite green: 327 passed, three consecutive randomized runs. ruff format, ruff check --no-fix
and ty check clean.

Litestar strips the trailing slash out of scope["path"], so an excluded entry
carrying one never matched the URL OpenTelemetryMiddleware builds. The default
health_checks_path is "/health/", so opentelemetry_generate_health_check_spans=False
silently did nothing.

Closes #248
@lesnik512
lesnik512 merged commit e4c844e into main Sep 20, 2026
13 checks passed
@lesnik512
lesnik512 deleted the fix/248-litestar-trailing-slash-exclusion branch September 20, 2026 17:17
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.

Litestar never excludes a path with a trailing slash from tracing, so health-check spans are still recorded

1 participant