Logging isn’t just about debugging errors — it’s your window into what’s happening across every layer of your API. If you’re building with FastAPI and still using the plain old logging module, you might be missing out on massive productivity and clarity gains. Loguru, the Python logging library known for its painless setup, beautiful formatting, and powerful features.
This guide will walk you through a professional, production-ready FastAPI logging setup using Loguru — complete with code snippets, middleware, and essential tips inspired by real-world projects.
Why Loguru? (And Why Not Just Stick with Standard Logging?)
- Zero boilerplate: Start logging with a simple import; no need for logger build-up.
- Rich formatting: Colorized console logs, custom formats, and easy JSON output for ingestion by log aggregators
- Async and multiprocessing support: Play nicely with FastAPI, Uvicorn, Gunicorn, and all modern deployment patterns.
- Rotation, retention, and compression: Built-in file rotation and cleanup with a single line.
- Structured logs: Effortlessly output structured JSON for data-hungry systems.
Step 1: Install Loguru
pip install loguru
Step 2: Supercharge Your FastAPI Logging
Replace the cluttered defaults with a log setup that’s readable, maintainable, and ready for cloud deployments.
from fastapi import FastAPI, Request
from loguru import logger
import sys
app = FastAPI()
# Remove the default handler
logger.remove()
# Add a stylish, ready-to-parse sink
logger.add(
sys.stdout,
level="DEBUG",
format="<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | <level>{level: <7}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>",
colorize=True,
backtrace=True,
diagnose=True,
enqueue=True,
)
@app.get("/ping")
async def ping():
logger.info("Ping endpoint called")
return {"message": "pong"}
Tip: Set enqueue=True when using Uvicorn/Gunicorn for safe concurrent logging.
Step 3: Add Middleware to Log Every Request
For truly legendary logs, capture method, URL, headers, and even timing — all as each request flows in.
@app.middleware("http")
async def log_requests(request: Request, call_next):
logger.debug(f"{request.method} {request.url}")
logger.debug(f"Headers: {dict(request.headers)}")
response = await call_next(request)
logger.debug(f"Completed with status {response.status_code}")
return response
Customize this middleware to log path params, body, or custom context as needed.
Step 4: Structured and JSON Logs for Production
If you’re shipping logs to a log management platform (think DataDog, ELK, or BetterStack), output structured JSON:
logger.remove()
logger.add(sys.stdout, serialize=True)
Now your logs are machine-parseable, with every field (timestamp, level, message, request id, etc.) easily separated for dashboards and alerts.
Step 5: File Rotation and Retention Made Simple
Never lose logs or run out of disk space — let Loguru handle it:
logger.add(
"logs/app.log",
rotation="10 MB", # or "00:00" for daily rotation
retention="20 days",
compression="zip",
level="INFO",
enqueue=True,
)
Loguru automatically rotates, compresses, and deletes old logs for you.
Key Practices for Loguru + FastAPI
- Use one log configuration per worker in multiprocess setups — enabling
enqueue=Trueensures logs from different processes are safely written. - Add contextual info (user id, request id) via middleware or by customizing the log record format for powerful debugging and tracing.
- Use debugging and backtrace mode during development — then tune log level and destinations for production.
Loguru brings premium, scalable, and developer-friendly logging to your FastAPI apps with just a few lines of code.
Please like and follow for more!
