Debugging Guide¶
This guide covers debugging techniques and tools for litestar-pydotorg.
Debug Mode¶
Enable Debug Mode¶
Set in your .env file:
DEBUG=true
This enables:
Detailed error pages with stack traces
SQL query logging
Debug toolbar (if installed)
More verbose logging
Database Query Logging¶
# In .env
DATABASE_ECHO=true
All SQL queries will be logged to console.
Using Breakpoints¶
Python Built-in Debugger¶
# Add breakpoint in code
breakpoint()
# When execution reaches this line, you'll enter pdb
Common pdb commands:
n- Next lines- Step into functionc- Continue executionl- List source codep variable- Print variableq- Quit debugger
IPython Debugger¶
For a better debugging experience, use ipdb:
import ipdb; ipdb.set_trace()
Install with:
uv pip install ipdb
Logging¶
Basic Logging¶
import logging
logger = logging.getLogger(__name__)
# Different log levels
logger.debug("Detailed debug info")
logger.info("General information")
logger.warning("Warning message")
logger.error("Error occurred")
logger.critical("Critical error")
# Log with exception info
try:
risky_operation()
except Exception:
logger.error("Operation failed", exc_info=True)
Structured Logging¶
import structlog
logger = structlog.get_logger()
logger.info("user_created", user_id="123", email="test@example.com")
logger.error("operation_failed", error_code="E001", details={"reason": "timeout"})
Configure Log Level¶
# In .env
LOG_LEVEL=DEBUG
Debugging HTTP Requests¶
Request Inspection¶
from litestar import Request, get
@get("/debug")
async def debug_endpoint(request: Request) -> dict:
return {
"method": request.method,
"url": str(request.url),
"headers": dict(request.headers),
"query_params": dict(request.query_params),
"path_params": request.path_params,
}
Response Debugging¶
from litestar import Response
@get("/debug-response")
async def debug_response() -> Response:
response = Response(
content={"message": "debug"},
headers={"X-Debug": "true"}
)
# Log response before sending
logger.debug(f"Response: {response}")
return response
Database Debugging¶
Query Inspection¶
from sqlalchemy import event
from sqlalchemy.engine import Engine
@event.listens_for(Engine, "before_cursor_execute")
def receive_before_cursor_execute(conn, cursor, statement, parameters, context, executemany):
logger.debug(f"SQL: {statement}")
logger.debug(f"Params: {parameters}")
Connection Pool Status¶
from pydotorg.core.database import engine
# Check pool status
pool = engine.pool
logger.info(f"Pool size: {pool.size()}")
logger.info(f"Checked out: {pool.checkedout()}")
logger.info(f"Overflow: {pool.overflow()}")
Interactive Database Shell¶
# PostgreSQL shell
psql $DATABASE_URL
# Python shell with app context
uv run python scripts/shell.py
Debugging Background Tasks¶
SAQ Worker Logging¶
# Start worker with verbose logging
LOG_LEVEL=DEBUG uv run python -m saq worker pydotorg.tasks.base.worker
Task Inspection¶
from pydotorg.tasks.base import queue
# Get queue status
async def check_queue():
stats = await queue.stats()
logger.info(f"Queue stats: {stats}")
# List pending jobs
jobs = await queue.jobs()
for job in jobs:
logger.info(f"Job: {job.id}, Status: {job.status}")
Memory Debugging¶
Memory Profiling¶
import tracemalloc
tracemalloc.start()
# ... your code ...
current, peak = tracemalloc.get_traced_memory()
logger.info(f"Current memory: {current / 10**6:.1f} MB")
logger.info(f"Peak memory: {peak / 10**6:.1f} MB")
tracemalloc.stop()
Object Reference Tracking¶
import gc
import sys
# Force garbage collection
gc.collect()
# Count objects of a type
user_count = sum(1 for obj in gc.get_objects() if isinstance(obj, User))
logger.info(f"User objects in memory: {user_count}")
Performance Debugging¶
Request Timing Middleware¶
import time
from litestar import Litestar, Request
from litestar.middleware import MiddlewareProtocol
class TimingMiddleware(MiddlewareProtocol):
async def __call__(self, scope, receive, send):
start = time.perf_counter()
await self.app(scope, receive, send)
elapsed = time.perf_counter() - start
logger.info(f"Request took {elapsed:.3f}s")
Profile Specific Code¶
import cProfile
import pstats
def profile_function():
profiler = cProfile.Profile()
profiler.enable()
# Code to profile
result = expensive_operation()
profiler.disable()
stats = pstats.Stats(profiler).sort_stats("cumulative")
stats.print_stats(10) # Top 10 functions
return result
Debugging Tests¶
Run Single Test with Output¶
uv run pytest tests/unit/test_file.py::test_name -v -s
Debug Failing Tests¶
# Enter debugger on failure
uv run pytest --pdb
# Enter debugger on first failure and stop
uv run pytest -x --pdb
Show Local Variables¶
uv run pytest -l # Show locals in tracebacks
IDE Debugging¶
VS Code¶
Create
.vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"name": "Python: Litestar",
"type": "python",
"request": "launch",
"module": "litestar",
"args": ["run", "--reload"],
"env": {
"LITESTAR_APP": "pydotorg.main:app"
},
"console": "integratedTerminal"
},
{
"name": "Python: Current File",
"type": "python",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal"
}
]
}
Set breakpoints by clicking in the gutter
Press F5 to start debugging
PyCharm¶
Right-click on file and select “Debug”
Set breakpoints by clicking in the gutter
Use debug panel to inspect variables
Common Issues¶
Import Errors¶
# Check Python path
uv run python -c "import sys; print(sys.path)"
# Verify package installation
uv pip show pydotorg
Connection Issues¶
# Test database connection
uv run python -c "
from pydotorg.core.database import engine
import asyncio
async def test():
async with engine.begin() as conn:
await conn.execute('SELECT 1')
print('Database OK')
asyncio.run(test())
"
# Test Redis connection
uv run python -c "
import redis
r = redis.from_url('redis://localhost:6379')
print('Redis:', r.ping())
"
Environment Issues¶
# Print all environment variables
uv run python -c "
import os
for key, value in sorted(os.environ.items()):
if 'PYDOTORG' in key or 'DATABASE' in key:
print(f'{key}={value}')
"
Troubleshooting Checklist¶
Check if services are running:
docker-compose psVerify environment variables:
cat .envCheck database connection:
psql $DATABASE_URL -c "SELECT 1"Check Redis connection:
redis-cli pingReview logs:
docker-compose logs -fClear cache:
redis-cli FLUSHALLRestart services:
make infra-down && make infra-upReinstall dependencies:
make install