Basic Logging in Fastapi using Logger module
Source: Dev.to
When an Application Crashes in Production
An application crashed in production and users weren’t sure what to do next.
I experienced this last year on a project I was working on. As the programmer, I had to race to the terminal to check the error and start debugging.
It wasn’t a pleasant experience—until a senior developer introduced me to catching and logging errors. I was familiar with the concepts but had never applied them in real life. After adding proper error handling, my programming life got a lot smoother.
Benefits of Logging and Catching Errors
- Faster Debugging – Logs tell you what happened, when it happened, where it happened, and who triggered it.
- Better Error Visibility in Production – In production you can’t print errors or attach a debugger. Logs are your only window into the production environment, which is especially critical for remote servers and APIs consumed by external clients.
- Graceful Failure (Better UX) – Catching errors lets you return meaningful HTTP responses, avoid crashing the entire app, and keep services running even when something fails.
- Security and Auditing – Logs help you detect suspicious behaviour, track who accessed what, and audit sensitive operations.
Practical Approach: Logging & Error Handling in FastAPI
Below is a minimal e‑commerce example that demonstrates how to set up logging and error handling in a FastAPI application.
Folder Structure

schemas.py – Define Your Pydantic Models
from pydantic import BaseModel
from enum import Enum
class Status(str, Enum):
AVAILABLE = "AVAILABLE"
UNAVAILABLE = "UNAVAILABLE"
class ProductBase(BaseModel):
name: str
description: str
price: float
status: Status
class ProductCreate(ProductBase):
pass
class ProductUpdate(BaseModel):
name: str | None = None
description: str | None = None
price: float | None = None
status: Status | None = None
class Product(ProductBase):
id: int
main.py – Set Up FastAPI, Logging, and In‑Memory “Database”
from fastapi import FastAPI, HTTPException, status, Response
import logging
from app.schemas import Product, ProductCreate, ProductUpdate
app = FastAPI()
# Configure logging – all logs go to app.log
logging.basicConfig(
filename="app.log",
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s",
)
logger = logging.getLogger(__name__)
# In‑memory list acting as a simple database
products: list[dict] = []
def fetch_product(product_id: int) -> dict | None:
"""Return a product dict matching the given id, or None if not found."""
for product in products:
if product["id"] == product_id:
return product
return None
Endpoints – Retrieve All Products & a Single Product
@app.get("/", response_model=list[Product])
def get_products():
"""Return the list of all products."""
try:
return products
except Exception as e:
logger.error(f"Unexpected error while getting products: {e}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="An unexpected error occurred while getting products",
)
@app.get("/{product_id}", response_model=Product)
def get_product(product_id: int):
"""Return a single product by its id."""
try:
product = fetch_product(product_id)
if not product:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Product not found"
)
return product
except Exception as e:
logger.error(f"Unexpected error while getting product {product_id}: {e}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="An unexpected error occurred while getting the product",
)
Notice the try/except blocks:
- If something goes wrong (e.g.,
productsis undefined), the exception is logged and the client receives a generic 500 response instead of a raw traceback.
Example: Creating a Product (with intentional error for demo)
@app.post("/", status_code=status.HTTP_201_CREATED, response_model=Product)
def create_product(product: ProductCreate):
"""Create a new product and add it to the in‑memory list."""
try:
# Uncomment the line below to simulate a coding error and see logging in action
# kkk # <-- intentional NameError for demonstration
product_data = product.model_dump()
product_data["id"] = len(products) + 1
products.append(product_data)
return product_data
except Exception as e:
logger.error(f"Unexpected error while creating product: {e}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="An unexpected error occurred while creating the product",
)
If you insert a syntax or runtime error (e.g., the kkk line), the exception will be caught, logged to app.log, and the client will receive a clean 500 response.
Running the Application
-
Create a virtual environment (optional but recommended).
-
Install dependencies:
pip install fastapi uvicorn -
Start the server:
uvicorn main:app --reloadThe
--reloadflag enables auto‑reloading during development. -
Test the endpoints (e.g., with
curl, HTTPie, Postman, or a browser). -
Check the logs – Open
app.logto see the recorded messages whenever an exception occurs.
TL;DR
- Log everything you need to know about errors.
- Catch exceptions at the API‑boundary level to return user‑friendly responses.
- Never expose raw tracebacks to end users; keep them in logs for developers.
Implementing these practices makes your production services more reliable, debuggable, and secure. Happy coding!
Basic Logging in FastAPI
When an error occurs while creating a product, you might see a message like:
error occurred while creating the product')
How to View the Logs
- Run the
create_productendpoint. - Open the
app.logfile that is generated.
The file will automatically update with any new errors that occur.

This is basic error logging in FastAPI.