diff --git a/backend/api/core/config.py b/backend/api/core/config.py index 0e0d010f..87160760 100644 --- a/backend/api/core/config.py +++ b/backend/api/core/config.py @@ -168,6 +168,10 @@ def has_local_fallback(self) -> bool: # Entra USE_ENTRA_AUTH: bool = os.getenv("USE_ENTRA_AUTH", "false").lower() == "true" + # Azure App Insights + USE_APP_INSIGHTS: bool = os.getenv("USE_APP_INSIGHTS", "false").lower() == "true" + APP_INSIGHTS_CONNECTION_STRING: Optional[str] = os.getenv("APP_INSIGHTS_CONNECTION_STRING") + class Config: case_sensitive = True # Resolve to backend/.env regardless of current working directory. diff --git a/backend/api/services/app_insights_service.py b/backend/api/services/app_insights_service.py new file mode 100644 index 00000000..7a9261e7 --- /dev/null +++ b/backend/api/services/app_insights_service.py @@ -0,0 +1,29 @@ +from api.core.config import settings +from azure.identity import DefaultAzureCredential +from azure.monitor.opentelemetry import configure_azure_monitor +import logging + +def configure_azure_app_insights(): + if settings.USE_APP_INSIGHTS and not settings.APP_INSIGHTS_CONNECTION_STRING: + raise ValueError("APP_INSIGHTS_CONNECTION_STRING must be set if USE_APP_INSIGHTS is true") + + if settings.USE_APP_INSIGHTS and settings.APP_INSIGHTS_CONNECTION_STRING: + credential = DefaultAzureCredential() + configure_azure_monitor(connection_string=settings.APP_INSIGHTS_CONNECTION_STRING, credential=credential) + # Suppress noisy Azure SDK internal logs from terminal and App Insights traces + for noisy_logger in [ + "azure.core.pipeline.policies.http_logging_policy", + "azure.monitor.opentelemetry.exporter", + ]: + logging.getLogger(noisy_logger).setLevel(logging.WARNING) + print("📈 Application Insights enabled", flush=True) + + +def log_action(s, user=None): + logger = logging.getLogger("actions_of_interest") + logger.setLevel(logging.INFO) + if user: + extra = {"custom_dimensions": {"user": user.name}} + logger.info(s, extra=extra) + else: + logger.info(s) \ No newline at end of file diff --git a/backend/main.py b/backend/main.py index 2b610d25..bbff5b14 100644 --- a/backend/main.py +++ b/backend/main.py @@ -1,4 +1,5 @@ import os +from api.services.app_insights_service import log_action import uvicorn from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware @@ -44,6 +45,15 @@ async def startup_event(): print("✓ Users table initialized", flush=True) except Exception as e: print(f"⚠️ Failed to ensure users table exists: {e}", flush=True) + + # Configure Azure Application Insights if enabled + if settings.USE_APP_INSIGHTS: + try: + from api.services.app_insights_service import configure_azure_app_insights + configure_azure_app_insights() + log_action("Application Insights configured") + except Exception as e: + print(f"⚠️ Failed to configure Azure Application Insights: {e}", flush=True) print("🎯 CAN-SR Backend ready!", flush=True) diff --git a/backend/requirements.txt b/backend/requirements.txt index 8e33d34a..7541714b 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -41,4 +41,6 @@ langchain-google-genai==4.2.0 # OAuth Authlib==1.6.6 -itsdangerous==2.2.0 \ No newline at end of file +itsdangerous==2.2.0 + +azure-monitor-opentelemetry==1.8.6 \ No newline at end of file