Errors & Logging Best Practices
Operational rules for exceptions and logs in production Python services.
Search across all documentation pages
Operational rules for exceptions and logs in production Python services.
pytest, -W error, log format tests).except: in application code.raise DomainError() from exc at boundaries. Preserve root cause in logs and Sentry.BillingError, not Exception.AssertionError and TypeError bubble in dev; fix code.except* in async TaskGroup code. Do not assume single failure.getLogger(__name__).% formatting: log.info("id=%s", id). Avoid f-strings in log calls.urllib3, asyncio - filter by module, document why.request_id, user_id, duration_ms.contextvars for request-scoped fields.log.exception inside except. One stack per incident, not duplicate prints."payment_failed" + order_id=, not interpolated sentences.DeprecationWarning and removal version. Run CI with warnings as errors for your code.stacklevel=2+ in warning wrappers. Blame caller line in traceback.suppress only for truly optional paths.pytest.raises, deprecated_call.Bare except: pass - hides data corruption until reconciliation fails weeks later.
Yes at boundaries when operators need visibility and callers need failure - not on every inner loop.
ruff E722, pytest with filterwarnings=error, and integration tests asserting log JSON schema.
print for notebooks and one-off scripts; logging for anything deployed.
One line per successful request boundary; DEBUG for internals. High-cardinality per-row INFO floods aggregators.
Complementary - Sentry groups stack traces; logs give chronological context. Wire both with same release tag.
Wrap once at adapter boundary into domain error; log original with from exc.
Libraries log context at WARNING/ERROR; application decides handlers and final user message.
Use async-friendly handlers or queue to thread; avoid blocking IO on event loop thread.
Replace with log.debug and run locally at DEBUG; remove before merge or gate behind flag.
Stack versions: This page was written for Python 3.14.0 (stable 3.14, maintenance 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, and uv 0.6+.
Reviewed by Chris St. John·Last updated Jul 19, 2026