Week 12: Observability & Production Readiness

Build the next production-ready layer of your FastAPI service through clear concepts, a focused implementation and a practical exercise.

Module 9 of 12Week 12 of 15~3-4 HoursHands-on Exercise Included

By the end of this week, you'll be able to

  • Structured logs and request IDs
  • Liveness and readiness checks
  • Prometheus metrics and tracing context

1. Structured logs and request IDs

Start with the contract: make inputs, outputs and failure behavior explicit before adding infrastructure. This keeps the feature easy to reason about and gives tests a stable boundary.

2. Liveness and readiness checks

Apply the pattern through a small vertical slice. Keep framework wiring at the edge and business decisions in focused functions or services that can be tested without starting the whole application.

core example
@app.get("/health/ready")
async def readiness():
    await database.execute(text("SELECT 1"))
    return {"status": "ready"}

REQUESTS = Counter("http_requests_total", "Requests", ["method", "route", "status"])

3. Prometheus metrics and tracing context

Treat failure paths as part of the design. Add bounded resource usage, meaningful errors and a verification step so the behavior remains dependable under real production conditions.

4. Hands-on Exercise

Build the feature

Add JSON logs with correlation IDs, separate live/ready endpoints, and request latency and count metrics without using raw URLs as labels.

Definition of done

  • The happy path works through the real HTTP boundary.
  • At least one failure path is handled and tested.
  • Configuration and secrets stay outside source code.
  • The README explains how to run and verify the result.

5. Knowledge Check

Why should liveness not fail merely because the database is briefly unavailable?

Show answer

A restart cannot repair an external dependency and may create a restart loop; dependency checks belong in readiness.