Skip to content

Latest commit

 

History

History
124 lines (102 loc) · 6.09 KB

File metadata and controls

124 lines (102 loc) · 6.09 KB

lite-bootstrap 1.4.0 — Litestar access logging off by default

1.4.0 is a minor release with a behavior change for Litestar services. A second bootstrapper sharing an application also now fails loudly instead of corrupting it — see Bug fixes below.

Behavior change

Litestar's LoggingMiddleware no longer logs requests and responses by default. If your service is on Litestar and you rely on the HTTP Request / HTTP Response access log lines it used to emit, they stop appearing after this upgrade until you opt back in:

LitestarConfig(
    service_name="microservice",
    litestar_logging_middleware_enabled=True,
)

Why

LitestarLoggingInstrument registers Litestar's StructlogPlugin, and Litestar's own default LoggingMiddlewareConfig logs full request and response bodies. That meant:

  • Any credential posted to the service — a login form's password, an API key in a JSON body — landed in stdout verbatim. Litestar only obfuscates the Authorization / X-API-KEY headers and the session cookie; request and response bodies are never obfuscated.
  • Every offline Swagger asset served by swagger_offline_docs=True (swagger-ui-bundle.js, swagger-ui.css, up to ~150 KB) was logged as an ordinary response body on every request.
  • Every k8s health probe and every Prometheus scrape produced its own log line, unconditionally.

None of this was opt-in — it was a side effect of adding the plugin. Every other bootstrapper (FastAPI, FastStream, FastMCP, Free) adds no request/response logging middleware at all, so this brings Litestar in line with the rest.

What the opt-in logs

With litestar_logging_middleware_enabled=True, access logs are metadata only:

  • Requests: path, method, content_type, path_params.
  • Responses: status_code.

No body, headers, cookies, or query — bodies and headers are where secrets live, and query strings carry tokens often enough to not be worth the diagnostic value. Note that path and path_params are still logged, so a secret embedded in the URL itself (e.g. /reset-password/{token}) is recorded; keep secrets in the body, never in the path.

The opt-in also excludes infrastructure routes from access logs: the Swagger docs path, the offline Swagger static assets (when swagger_offline_docs is on), the health-check path, and the Prometheus metrics path — each matched whether or not the corresponding instrument is actually active, so a service that disables health checks but serves its own route at the same path is still excluded there.

Escape hatch

To take full control — including restoring Litestar's original body-logging defaults — pass your own LoggingMiddlewareConfig via litestar_logging_middleware_config. It replaces the hardened defaults above wholesale, with no merging:

from litestar.middleware.logging import LoggingMiddlewareConfig

LitestarConfig(
    service_name="microservice",
    litestar_logging_middleware_enabled=True,
    litestar_logging_middleware_config=LoggingMiddlewareConfig(
        request_log_fields=("path", "method", "content_type"),
    ),
)

Supplying litestar_logging_middleware_config while litestar_logging_middleware_enabled is False is a no-op that emits a warning — set the flag to actually turn logging on.

Bug fixes

  • Litestar apps can read request bodies again. Litestar.from_config() — which LitestarBootstrapper uses — passes every AppConfig field explicitly, so the 10 MB request_max_body_size default that Litestar(...) applies never reached the built app. Every handler taking a request body returned 500: 'request_max_body_size' set to 'Empty' on all layers unless the caller set the field themselves. The bootstrapper now fills it when the config leaves it unset; a caller's own value, including an explicit None for no limit, is untouched. Reported upstream as litestar#4296.
  • Structlog output follows a redirected stdout. _MemoryLoggerFactoryConfig.log_stream bound sys.stdout once, at import time, so a process that replaced sys.stdout after importing lite_bootstrap but before bootstrapping kept logging to the stale stream — while the root-logger handler installed at bootstrap followed the new one. The stream is now resolved at bootstrap, so both agree. Affects every bootstrapper.
  • The litestar extra's floor moved from >=2.9 to >=2.15. AppConfig.request_max_body_size, which the fix above now reads, was only added in litestar 2.13; and litestar.middleware.ASGIMiddleware, which the OpenTelemetry middleware already subclassed before this release, was only added in litestar 2.15. >=2.9 was never actually supported for the OTel path — this just makes the declared floor honest.
  • A second bootstrapper sharing an application now fails loudly instead of corrupting it. Constructing two bootstrappers (FastAPI, Litestar, FastStream, or FastMCP) against the same application already warned at construction time, but bootstrap() on the second one applied every instrument again anyway. Litestar died with an unrelated-looking ImproperlyConfiguredException: Handler already registered for path '/health' and http method OPTIONS; FastAPI did not fail at all — the app's route count silently grew (e.g. from 6 to 8 for a default config), a shadowed duplicate of the health-check and metrics routes. bootstrap() on the losing bootstrapper now raises ConfigurationError naming itself. If your code relied on the FastAPI case appearing to "work", it will now raise. The ownership marker behind this is never cleared, including by teardown() — once an application has been bootstrapped, it stays owned for the life of the process; construct a fresh application rather than reusing one that was already bootstrapped.

References

  • planning/changes/2026-08-10.01-litestar-middleware-logging.md
  • planning/changes/2026-08-10.02-log-stream-bind-at-bootstrap.md
  • planning/changes/2026-08-10.03-litestar-request-max-body-size.md
  • planning/changes/2026-08-10.04-double-bootstrap-guard.md