diff --git a/database.py b/database.py index f01e05f..d6fef8e 100644 --- a/database.py +++ b/database.py @@ -17,7 +17,13 @@ url = URL.create( port=ApplicationConfig.POSTGRES_PORT ) -engine = create_engine(url) +engine = create_engine( + url, + pool_pre_ping=True, # Verify connections before use + pool_size=5, # Maintain 5 connections in pool + max_overflow=10, # Allow 10 additional connections when busy + pool_recycle=3600, # Recycle connections after 1 hour +) Session = sessionmaker(autocommit=False, autoflush=False, bind=engine) session = Session() diff --git a/main.py b/main.py index 8d6e544..7ea49e1 100644 --- a/main.py +++ b/main.py @@ -1,8 +1,10 @@ import logging import sys -from fastapi import FastAPI +import uuid +from fastapi import FastAPI, Request from app.routers import delivery from fastapi.middleware.cors import CORSMiddleware +from starlette.middleware.base import BaseHTTPMiddleware from config import load_config from sqlalchemy import create_engine, text from sqlalchemy.orm import sessionmaker @@ -10,17 +12,38 @@ from sqlalchemy.orm import sessionmaker ApplicationConfig = load_config() -# Configure logging -logging.basicConfig( - level=logging.INFO, - format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', - datefmt='%Y-%m-%d %H:%M:%S', - handlers=[logging.StreamHandler(sys.stdout)] -) -logger = logging.getLogger('eamco_money_api') +# Configure logging - DEBUG in development, INFO in production +def setup_logging(): + log_level = logging.DEBUG if ApplicationConfig.CURRENT_SETTINGS != 'PRODUCTION' else logging.INFO -# Database setup -engine = create_engine(ApplicationConfig.SQLALCHEMY_DATABASE_URI) + formatter = logging.Formatter( + '%(asctime)s - %(name)s - %(levelname)s - %(message)s', + datefmt='%Y-%m-%d %H:%M:%S' + ) + + root_logger = logging.getLogger() + root_logger.setLevel(log_level) + root_logger.handlers.clear() + + console_handler = logging.StreamHandler(sys.stdout) + console_handler.setLevel(log_level) + console_handler.setFormatter(formatter) + root_logger.addHandler(console_handler) + + logging.getLogger('uvicorn.access').setLevel(logging.WARNING) + + return logging.getLogger('eamco_money_api') + +logger = setup_logging() + +# Database setup with connection pooling +engine = create_engine( + ApplicationConfig.SQLALCHEMY_DATABASE_URI, + pool_pre_ping=True, + pool_size=5, + max_overflow=10, + pool_recycle=3600, +) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) def check_db_connection(): @@ -37,6 +60,18 @@ def check_db_connection(): app = FastAPI() + +# Request ID middleware for request tracking/correlation +class RequestIDMiddleware(BaseHTTPMiddleware): + async def dispatch(self, request: Request, call_next): + request_id = request.headers.get("X-Request-ID") or str(uuid.uuid4())[:8] + request.state.request_id = request_id + response = await call_next(request) + response.headers["X-Request-ID"] = request_id + return response + +app.add_middleware(RequestIDMiddleware) + app.include_router(delivery.router) @@ -61,7 +96,11 @@ async def startup_event(): logger.info("🤖🤖🤖🤖🤖 Mode: Development 🤖🤖🤖🤖🤖") elif mode in ['PRODUCTION', 'PROD']: logger.info("💀💀💀💀💀💀💀💀💀💀 ⚠️ WARNING PRODUCTION 💀💀💀💀💀💀💀💀💀💀") - logger.info(f"DB: {ApplicationConfig.SQLALCHEMY_DATABASE_URI[:30]}...") + # Sanitize DB URI to avoid logging credentials + db_uri = ApplicationConfig.SQLALCHEMY_DATABASE_URI + if '@' in db_uri: + db_uri = db_uri.split('@')[-1] + logger.info(f"DB: ...@{db_uri[:50]}") logger.info(f"CORS: {len(ApplicationConfig.origins)} origins configured") # Test database connection