From 216160ad2667c49dbba9006a82f4ff503a72f17e Mon Sep 17 00:00:00 2001 From: Ajit Padhi Date: Tue, 3 Mar 2026 15:45:41 +0530 Subject: [PATCH 1/6] fixed app insights logging issue --- content-gen/src/backend/app.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/content-gen/src/backend/app.py b/content-gen/src/backend/app.py index 1e2a41b80..884d927f3 100644 --- a/content-gen/src/backend/app.py +++ b/content-gen/src/backend/app.py @@ -24,6 +24,7 @@ from services.blob_service import get_blob_service from services.title_service import get_title_service from api.admin import admin_bp +from azure.monitor.opentelemetry import configure_azure_monitor # In-memory task storage for generation tasks # In production, this should be replaced with Redis or similar @@ -37,6 +38,16 @@ logging.getLogger("azure.core.pipeline.policies.http_logging_policy").setLevel(logging.WARNING) logger = logging.getLogger(__name__) +# Check if the Application Insights Instrumentation Key is set in the environment variables +instrumentation_key = os.getenv("APPLICATIONINSIGHTS_CONNECTION_STRING") +if instrumentation_key: + # Configure Application Insights if the Instrumentation Key is found + configure_azure_monitor(connection_string=instrumentation_key) + logging.info("Application Insights configured with the provided Instrumentation Key") +else: + # Log a warning if the Instrumentation Key is not found + logging.warning("No Application Insights Instrumentation Key found. Skipping configuration") + # Create Quart app app = Quart(__name__) app = cors(app, allow_origin="*") From a8b2519a37da8f6470b00d578946e846a76e26e5 Mon Sep 17 00:00:00 2001 From: Ajit Padhi Date: Tue, 3 Mar 2026 16:07:59 +0530 Subject: [PATCH 2/6] requirement file updated --- content-gen/src/backend/requirements.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/content-gen/src/backend/requirements.txt b/content-gen/src/backend/requirements.txt index e1471c19e..0b8cd1358 100644 --- a/content-gen/src/backend/requirements.txt +++ b/content-gen/src/backend/requirements.txt @@ -26,6 +26,9 @@ openai>=1.45.0 # HTTP Client (for Foundry direct API calls) httpx>=0.27.0 +# Monitoring / Telemetry +azure-monitor-opentelemetry>=1.6.0 + # Data Validation pydantic>=2.8.0 pydantic-settings>=2.4.0 From 18dfa2f5b859efa496a23a17f58868cf5a93e1b1 Mon Sep 17 00:00:00 2001 From: Ajit Padhi Date: Tue, 3 Mar 2026 16:33:39 +0530 Subject: [PATCH 3/6] updated logging config --- content-gen/src/backend/app.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/content-gen/src/backend/app.py b/content-gen/src/backend/app.py index 884d927f3..e1a429630 100644 --- a/content-gen/src/backend/app.py +++ b/content-gen/src/backend/app.py @@ -38,15 +38,15 @@ logging.getLogger("azure.core.pipeline.policies.http_logging_policy").setLevel(logging.WARNING) logger = logging.getLogger(__name__) -# Check if the Application Insights Instrumentation Key is set in the environment variables -instrumentation_key = os.getenv("APPLICATIONINSIGHTS_CONNECTION_STRING") -if instrumentation_key: - # Configure Application Insights if the Instrumentation Key is found - configure_azure_monitor(connection_string=instrumentation_key) - logging.info("Application Insights configured with the provided Instrumentation Key") +# Check if the Application Insights connection string is set in the environment variables +appinsights_connection_string = os.getenv("APPLICATIONINSIGHTS_CONNECTION_STRING") +if appinsights_connection_string: + # Configure Application Insights if the connection string is found + configure_azure_monitor(connection_string=appinsights_connection_string) + logger.info("Application Insights configured with the provided connection string") else: - # Log a warning if the Instrumentation Key is not found - logging.warning("No Application Insights Instrumentation Key found. Skipping configuration") + # Log a warning if the connection string is not found + logger.warning("No Application Insights connection string found. Skipping configuration") # Create Quart app app = Quart(__name__) From ada9183e56ac56932c7b14ba0c749297983d0ae7 Mon Sep 17 00:00:00 2001 From: Ajit Padhi Date: Mon, 9 Mar 2026 15:11:49 +0530 Subject: [PATCH 4/6] updated logging config --- content-gen/infra/main.bicep | 2 + content-gen/src/backend/app.py | 61 +++++++++++++++++++++--- content-gen/src/backend/requirements.txt | 1 + 3 files changed, 58 insertions(+), 6 deletions(-) diff --git a/content-gen/infra/main.bicep b/content-gen/infra/main.bicep index c3b840d2c..3da569e2d 100644 --- a/content-gen/infra/main.bicep +++ b/content-gen/infra/main.bicep @@ -869,6 +869,8 @@ module containerInstance 'modules/container-instance.bicep' = { { name: 'AZURE_AI_PROJECT_ENDPOINT', value: aiFoundryAiProjectEndpoint } { name: 'AZURE_AI_MODEL_DEPLOYMENT_NAME', value: gptModelName } { name: 'AZURE_AI_IMAGE_MODEL_DEPLOYMENT', value: imageModelConfig[imageModelChoice].name } + // Application Insights + { name: 'APPLICATIONINSIGHTS_CONNECTION_STRING', value: enableMonitoring ? applicationInsights!.outputs.connectionString : '' } ] } } diff --git a/content-gen/src/backend/app.py b/content-gen/src/backend/app.py index e1a429630..526ea4800 100644 --- a/content-gen/src/backend/app.py +++ b/content-gen/src/backend/app.py @@ -16,6 +16,7 @@ from quart import Quart, request, jsonify, Response from quart_cors import cors +from opentelemetry import trace from settings import app_settings from models import CreativeBrief, Product @@ -24,7 +25,9 @@ from services.blob_service import get_blob_service from services.title_service import get_title_service from api.admin import admin_bp +from azure.core.settings import settings as azure_settings from azure.monitor.opentelemetry import configure_azure_monitor +from opentelemetry.instrumentation.asgi import OpenTelemetryMiddleware # In-memory task storage for generation tasks # In production, this should be replaced with Redis or similar @@ -35,27 +38,73 @@ level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s" ) -logging.getLogger("azure.core.pipeline.policies.http_logging_policy").setLevel(logging.WARNING) logger = logging.getLogger(__name__) +# Create Quart app +app = Quart(__name__) +app = cors(app, allow_origin="*") + # Check if the Application Insights connection string is set in the environment variables appinsights_connection_string = os.getenv("APPLICATIONINSIGHTS_CONNECTION_STRING") if appinsights_connection_string: # Configure Application Insights if the connection string is found - configure_azure_monitor(connection_string=appinsights_connection_string) + # logging_level=WARNING sends only WARNING/ERROR/CRITICAL to App Insights + # (INFO traces like "Loaded product", "Uploaded image", workflow steps stay in container logs only) + configure_azure_monitor( + connection_string=appinsights_connection_string, + enable_live_metrics=False, + logging_level=logging.WARNING, + ) + # Disable Azure SDK native span creation (ContainerProxy.*, BlobClient.* InProc spans) + azure_settings.tracing_implementation = None + # Apply ASGI middleware for request tracing (Quart is not auto-instrumented by configure_azure_monitor) + app.asgi_app = OpenTelemetryMiddleware( + app.asgi_app, + exclude_spans=["receive", "send"], + excluded_urls="api/generate/status", + ) logger.info("Application Insights configured with the provided connection string") else: # Log a warning if the connection string is not found logger.warning("No Application Insights connection string found. Skipping configuration") -# Create Quart app -app = Quart(__name__) -app = cors(app, allow_origin="*") - # Register blueprints app.register_blueprint(admin_bp) +@app.before_request +async def set_conversation_context(): + """Attach conversation_id and user_id to the current OTel span for App Insights.""" + conversation_id = "" + user_id = "" + + # 1. Extract from JSON body (POST requests) + if request.content_type and "json" in request.content_type: + try: + data = await request.get_json() + if data and isinstance(data, dict): + conversation_id = data.get("conversation_id", "") + user_id = data.get("user_id", "") + except Exception: + pass + + # 2. Extract from URL path parameters (e.g. /api/conversations/) + if not conversation_id and request.view_args: + conversation_id = request.view_args.get("conversation_id", "") + + # 3. Extract from query parameters (e.g. ?conversation_id=xxx) + if not conversation_id: + conversation_id = request.args.get("conversation_id", "") + + if not user_id: + user_id = request.args.get("user_id", "") or request.headers.get("X-Ms-Client-Principal-Id", "anonymous") + + span = trace.get_current_span() + if span.is_recording(): + span.set_attribute("conversation_id", conversation_id) + span.set_attribute("user_id", user_id) + + # ==================== Authentication Helper ==================== def get_authenticated_user(): diff --git a/content-gen/src/backend/requirements.txt b/content-gen/src/backend/requirements.txt index 0b8cd1358..60fd3913c 100644 --- a/content-gen/src/backend/requirements.txt +++ b/content-gen/src/backend/requirements.txt @@ -28,6 +28,7 @@ httpx>=0.27.0 # Monitoring / Telemetry azure-monitor-opentelemetry>=1.6.0 +opentelemetry-instrumentation-asgi>=0.48b0 # Data Validation pydantic>=2.8.0 From 8f12f4938ef91a0d95f7d59ea8333b8d5e18057f Mon Sep 17 00:00:00 2001 From: Ajit Padhi Date: Mon, 9 Mar 2026 16:58:04 +0530 Subject: [PATCH 5/6] updated logging --- content-gen/src/backend/app.py | 1 + 1 file changed, 1 insertion(+) diff --git a/content-gen/src/backend/app.py b/content-gen/src/backend/app.py index 526ea4800..8525c38fe 100644 --- a/content-gen/src/backend/app.py +++ b/content-gen/src/backend/app.py @@ -53,6 +53,7 @@ configure_azure_monitor( connection_string=appinsights_connection_string, enable_live_metrics=False, + enable_performance_counters=False, logging_level=logging.WARNING, ) # Disable Azure SDK native span creation (ContainerProxy.*, BlobClient.* InProc spans) From 0b3141675571338ce4708c605b53327ba5089d59 Mon Sep 17 00:00:00 2001 From: Ajit Padhi Date: Mon, 9 Mar 2026 18:36:21 +0530 Subject: [PATCH 6/6] updated logging changes --- content-gen/src/backend/app.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/content-gen/src/backend/app.py b/content-gen/src/backend/app.py index 8525c38fe..34c137bcf 100644 --- a/content-gen/src/backend/app.py +++ b/content-gen/src/backend/app.py @@ -81,13 +81,10 @@ async def set_conversation_context(): # 1. Extract from JSON body (POST requests) if request.content_type and "json" in request.content_type: - try: - data = await request.get_json() - if data and isinstance(data, dict): - conversation_id = data.get("conversation_id", "") - user_id = data.get("user_id", "") - except Exception: - pass + data = await request.get_json(silent=True) + if data and isinstance(data, dict): + conversation_id = data.get("conversation_id", "") + user_id = data.get("user_id", "") # 2. Extract from URL path parameters (e.g. /api/conversations/) if not conversation_id and request.view_args: