diff --git a/config/config-example.json b/config/config-example.json index d6cc9b11b..0cc629802 100644 --- a/config/config-example.json +++ b/config/config-example.json @@ -27,6 +27,8 @@ "LOG_LEVEL": "INFO", "LOG_FORMAT": "json", + "HOST": "0.0.0.0", + "PORT": "8000", "models": [ { diff --git a/src/main.py b/src/main.py index a9ecccf3f..587bf18d4 100644 --- a/src/main.py +++ b/src/main.py @@ -1,6 +1,8 @@ import logging +import sys import time -from collections.abc import Awaitable, Callable +from collections.abc import AsyncGenerator, Awaitable, Callable +from contextlib import asynccontextmanager from http import HTTPStatus from typing import Any @@ -16,16 +18,30 @@ from routers.probes import router as probes_router from services.metrics import CustomMetrics from utils.exceptions import K8sClientError -from utils.logging import get_logger +from utils.logging import get_logger, reconfigure_logging +from utils.settings import HOST, PORT logger = get_logger(__name__) access_logger = get_logger("access") + +@asynccontextmanager +async def lifespan(app: FastAPI) -> AsyncGenerator[None]: + """Lifespan event handler to reconfigure logging after uvicorn starts.""" + # Only reconfigure logging when NOT running tests + # During tests, logging is already configured by utils.logging on import + if "pytest" not in sys.modules: + # Reconfigure logging after uvicorn has applied its config + reconfigure_logging() + yield + + # Probe endpoints for efficient path checking PROBE_PATHS = frozenset(["/healthz", "/readyz"]) app = FastAPI( title="Joule", + lifespan=lifespan, ) @@ -189,5 +205,6 @@ async def metrics() -> Response: if __name__ == "__main__": # Logging is already configured in utils.logging - # Just run uvicorn without custom log config - uvicorn.run(app, host="0.0.0.0", port=8000) + # Disable uvicorn's log config to use our custom configuration + # Host and port are loaded from settings (configurable via environment variables) + uvicorn.run(app, host=HOST, port=PORT, log_config=None) diff --git a/src/utils/logging.py b/src/utils/logging.py index 6c2ae5f8a..aa5706c6b 100644 --- a/src/utils/logging.py +++ b/src/utils/logging.py @@ -85,6 +85,8 @@ def _configure_logging() -> None: # Configure root logger root_logger = logging.getLogger() root_logger.setLevel(LOG_LEVEL) + # Clear existing handlers to prevent duplicates when reconfiguring + root_logger.handlers.clear() root_logger.addHandler(console_handler) # Disable uvicorn.access logger (handled by middleware) diff --git a/src/utils/settings.py b/src/utils/settings.py index dbade6051..4e59c193f 100644 --- a/src/utils/settings.py +++ b/src/utils/settings.py @@ -72,6 +72,10 @@ def load_env_from_json() -> None: LOG_FORMAT = config("LOG_FORMAT", default="json") DEEPEVAL_TESTCASE_VERBOSE = config("DEEPEVAL_TESTCASE_VERBOSE", default="False") +# Server configuration - host and port for uvicorn +HOST = config("HOST", default="0.0.0.0") +PORT = config("PORT", default=8000, cast=int) + # Initialization of the main chat LLM models and main embedding model. MAIN_MODEL_NAME = config("MAIN_MODEL_NAME", default="gpt-4.1") MAIN_MODEL_MINI_NAME = config("MAIN_MODEL_MINI_NAME", default="gpt-4o-mini")