diff --git a/infra/main.bicep b/infra/main.bicep index fd2607343..c5b737428 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -1209,6 +1209,9 @@ module webSite 'modules/web-sites.bicep' = { UWSGI_THREADS: '2' APP_ENV: appEnvironment AZURE_CLIENT_ID: userAssignedIdentity.outputs.clientId + AZURE_BASIC_LOGGING_LEVEL: 'INFO' + AZURE_PACKAGE_LOGGING_LEVEL: 'WARNING' + AZURE_LOGGING_PACKAGES: '' } // WAF aligned configuration for Monitoring applicationInsightResourceId: enableMonitoring ? applicationInsights!.outputs.resourceId : null diff --git a/infra/main.json b/infra/main.json index 88d12077f..a8375bfe4 100644 --- a/infra/main.json +++ b/infra/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.38.33.27573", - "templateHash": "12469434193126673699" + "version": "0.37.4.10188", + "templateHash": "15752320925479265002" }, "name": "Document Generation Solution Accelerator", "description": "CSA CTO Gold Standard Solution Accelerator for Document Generation.\n" @@ -454,7 +454,7 @@ "logAnalyticsWorkspace": { "condition": "[and(parameters('enableMonitoring'), not(variables('useExistingLogAnalytics')))]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", + "apiVersion": "2022-09-01", "name": "[take(format('avm.res.operational-insights.workspace.{0}', variables('logAnalyticsWorkspaceResourceName')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -3560,7 +3560,7 @@ "applicationInsights": { "condition": "[parameters('enableMonitoring')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", + "apiVersion": "2022-09-01", "name": "[take(format('avm.res.insights.component.{0}', variables('applicationInsightsResourceName')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -4296,7 +4296,7 @@ }, "userAssignedIdentity": { "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", + "apiVersion": "2022-09-01", "name": "[take(format('avm.res.managed-identity.user-assigned-identity.{0}', variables('userAssignedIdentityResourceName')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -4779,7 +4779,7 @@ "virtualNetwork": { "condition": "[parameters('enablePrivateNetworking')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", + "apiVersion": "2022-09-01", "name": "[take(format('module.virtualNetwork.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -4816,8 +4816,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.38.33.27573", - "templateHash": "1734974014097019118" + "version": "0.37.4.10188", + "templateHash": "15908341678380884075" } }, "definitions": { @@ -5210,7 +5210,7 @@ }, "condition": "[not(empty(tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup')))]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", + "apiVersion": "2022-09-01", "name": "[take(format('avm.res.network.network-security-group.{0}.{1}', tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), parameters('resourceSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -5862,7 +5862,7 @@ }, "virtualNetwork": { "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", + "apiVersion": "2022-09-01", "name": "[take(format('avm.res.network.virtual-network.{0}', parameters('name')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -7589,7 +7589,7 @@ "bastionHost": { "condition": "[parameters('enablePrivateNetworking')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", + "apiVersion": "2022-09-01", "name": "[take(format('avm.res.network.bastion-host.{0}', variables('bastionHostName')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -8908,7 +8908,7 @@ "jumpboxVM": { "condition": "[parameters('enablePrivateNetworking')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", + "apiVersion": "2022-09-01", "name": "[take(format('avm.res.compute.virtual-machine.{0}', variables('jumpboxVmName')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -17258,7 +17258,7 @@ }, "condition": "[parameters('enablePrivateNetworking')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", + "apiVersion": "2022-09-01", "name": "[format('avm.res.network.private-dns-zone.{0}', split(variables('privateDnsZones')[copyIndex()], '.')[1])]", "properties": { "expressionEvaluationOptions": { @@ -20426,7 +20426,7 @@ "existingAiFoundryAiServicesDeployments": { "condition": "[variables('useExistingAiFoundryAiProject')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", + "apiVersion": "2022-09-01", "name": "[take(format('module.ai-services-model-deployments.{0}', variables('aiFoundryAiServicesResourceName')), 64)]", "subscriptionId": "[variables('aiFoundryAiServicesSubscriptionId')]", "resourceGroup": "[variables('aiFoundryAiServicesResourceGroupName')]", @@ -20475,8 +20475,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.38.33.27573", - "templateHash": "2501367807605442530" + "version": "0.37.4.10188", + "templateHash": "2655660447689660274" } }, "definitions": { @@ -20805,7 +20805,7 @@ "aiFoundryAiServices": { "condition": "[not(variables('useExistingAiFoundryAiProject'))]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", + "apiVersion": "2022-09-01", "name": "[take(format('avm.res.cognitive-services.account.{0}', variables('aiFoundryAiServicesResourceName')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -23418,8 +23418,8 @@ } }, "dependsOn": [ - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cognitiveServices)]", "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').aiServices)]", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cognitiveServices)]", "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').openAI)]", "logAnalyticsWorkspace", "userAssignedIdentity", @@ -23429,7 +23429,7 @@ "aiFoundryAiServicesProject": { "condition": "[not(variables('useExistingAiFoundryAiProject'))]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", + "apiVersion": "2022-09-01", "name": "[take(format('module.ai-project.{0}', variables('aiFoundryAiProjectResourceName')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -23462,8 +23462,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.38.33.27573", - "templateHash": "107641519342838452" + "version": "0.37.4.10188", + "templateHash": "16867891653751120909" } }, "parameters": { @@ -23574,7 +23574,7 @@ "searchServiceToExistingAiServicesRoleAssignment": { "condition": "[variables('useExistingAiFoundryAiProject')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", + "apiVersion": "2022-09-01", "name": "searchToExistingAiServices-roleAssignment", "subscriptionId": "[variables('aiFoundryAiServicesSubscriptionId')]", "resourceGroup": "[variables('aiFoundryAiServicesResourceGroupName')]", @@ -23600,8 +23600,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.38.33.27573", - "templateHash": "9717690292313179013" + "version": "0.37.4.10188", + "templateHash": "3644919950024112374" } }, "parameters": { @@ -23650,7 +23650,7 @@ }, "aiSearch": { "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", + "apiVersion": "2022-09-01", "name": "[take(format('avm.res.search.search-service.{0}', variables('aiSearchName')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -26026,7 +26026,7 @@ "existing_AIProject_SearchConnectionModule": { "condition": "[variables('useExistingAiFoundryAiProject')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", + "apiVersion": "2022-09-01", "name": "aiProjectSearchConnectionDeployment", "subscriptionId": "[variables('aiFoundryAiServicesSubscriptionId')]", "resourceGroup": "[variables('aiFoundryAiServicesResourceGroupName')]", @@ -26061,8 +26061,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.38.33.27573", - "templateHash": "11311597701635556530" + "version": "0.37.4.10188", + "templateHash": "6038840175458269917" } }, "parameters": { @@ -26129,7 +26129,7 @@ }, "storageAccount": { "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", + "apiVersion": "2022-09-01", "name": "[take(format('avm.res.storage.storage-account.{0}', variables('storageAccountName')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -31901,7 +31901,7 @@ }, "cosmosDB": { "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", + "apiVersion": "2022-09-01", "name": "[take(format('avm.res.document-db.database-account.{0}', variables('cosmosDBResourceName')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -35739,7 +35739,7 @@ }, "keyvault": { "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", + "apiVersion": "2022-09-01", "name": "[take(format('avm.res.key-vault.vault.{0}', variables('keyVaultName')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -35812,7 +35812,7 @@ }, { "name": "ADLS-ACCOUNT-KEY", - "value": "[listOutputsWithSecureValues('storageAccount', '2025-04-01').primaryAccessKey]" + "value": "[listOutputsWithSecureValues('storageAccount', '2022-09-01').primaryAccessKey]" }, { "name": "AZURE-COSMOSDB-ACCOUNT", @@ -35820,7 +35820,7 @@ }, { "name": "AZURE-COSMOSDB-ACCOUNT-KEY", - "value": "[listOutputsWithSecureValues('cosmosDB', '2025-04-01').primaryReadWriteKey]" + "value": "[listOutputsWithSecureValues('cosmosDB', '2022-09-01').primaryReadWriteKey]" }, { "name": "AZURE-COSMOSDB-DATABASE", @@ -35885,6 +35885,10 @@ { "name": "TENANT-ID", "value": "[subscription().tenantId]" + }, + { + "name": "AZURE-AI-AGENT-ENDPOINT", + "value": "[if(variables('useExistingAiFoundryAiProject'), format('https://{0}.services.ai.azure.com/api/projects/{1}', variables('aiFoundryAiServicesResourceName'), variables('aiFoundryAiProjectResourceName')), reference('aiFoundryAiServicesProject').outputs.apiEndpoint.value)]" } ] } @@ -39007,6 +39011,7 @@ } }, "dependsOn": [ + "aiFoundryAiServicesProject", "aiSearch", "avmPrivateDnsZones", "cosmosDB", @@ -39018,7 +39023,7 @@ }, "webServerFarm": { "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", + "apiVersion": "2022-09-01", "name": "[take(format('avm.res.web.serverfarm.{0}', variables('webServerFarmResourceName')), 64)]", "resourceGroup": "[resourceGroup().name]", "properties": { @@ -39592,7 +39597,7 @@ }, "webSite": { "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", + "apiVersion": "2022-09-01", "name": "[take(format('module.web-sites.{0}', variables('webSiteResourceName')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -39629,7 +39634,7 @@ } }, "configs": { - "value": "[concat(createArray(createObject('name', 'appsettings', 'properties', createObject('SCM_DO_BUILD_DURING_DEPLOYMENT', 'true', 'DOCKER_REGISTRY_SERVER_URL', format('https://{0}.azurecr.io', parameters('acrName')), 'AUTH_ENABLED', 'false', 'AZURE_SEARCH_SERVICE', reference('aiSearch').outputs.name.value, 'AZURE_SEARCH_INDEX', variables('azureSearchIndex'), 'AZURE_SEARCH_USE_SEMANTIC_SEARCH', variables('azureSearchUseSemanticSearch'), 'AZURE_SEARCH_SEMANTIC_SEARCH_CONFIG', variables('azureSearchSemanticSearchConfig'), 'AZURE_SEARCH_INDEX_IS_PRECHUNKED', 'True', 'AZURE_SEARCH_TOP_K', '5', 'AZURE_SEARCH_ENABLE_IN_DOMAIN', variables('azureSearchEnableInDomain'), 'AZURE_SEARCH_CONTENT_COLUMNS', variables('azureSearchContentColumns'), 'AZURE_SEARCH_FILENAME_COLUMN', variables('azureSearchUrlColumn'), 'AZURE_SEARCH_TITLE_COLUMN', '', 'AZURE_SEARCH_URL_COLUMN', '', 'AZURE_SEARCH_QUERY_TYPE', variables('azureSearchQueryType'), 'AZURE_SEARCH_VECTOR_COLUMNS', variables('azureSearchVectorFields'), 'AZURE_SEARCH_PERMITTED_GROUPS_COLUMN', '', 'AZURE_SEARCH_STRICTNESS', '3', 'AZURE_SEARCH_CONNECTION_NAME', variables('aiSearchConnectionName'), 'AZURE_OPENAI_API_VERSION', parameters('azureOpenaiAPIVersion'), 'AZURE_OPENAI_MODEL', parameters('gptModelName'), 'AZURE_OPENAI_ENDPOINT', format('https://{0}.openai.azure.com/', variables('aiFoundryAiServicesResourceName')), 'AZURE_OPENAI_RESOURCE', variables('aiFoundryAiServicesResourceName'), 'AZURE_OPENAI_PREVIEW_API_VERSION', parameters('azureOpenaiAPIVersion'), 'AZURE_OPENAI_GENERATE_SECTION_CONTENT_PROMPT', variables('azureOpenAiGenerateSectionContentPrompt'), 'AZURE_OPENAI_TEMPLATE_SYSTEM_MESSAGE', variables('azureOpenAiTemplateSystemMessage'), 'AZURE_OPENAI_TITLE_PROMPT', variables('azureOpenAiTitlePrompt'), 'AZURE_OPENAI_SYSTEM_MESSAGE', variables('azureOpenAISystemMessage'), 'AZURE_AI_AGENT_ENDPOINT', if(variables('useExistingAiFoundryAiProject'), format('https://{0}.services.ai.azure.com/api/projects/{1}', variables('aiFoundryAiServicesResourceName'), variables('aiFoundryAiProjectResourceName')), reference('aiFoundryAiServicesProject').outputs.apiEndpoint.value), 'AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME', parameters('gptModelName'), 'AZURE_AI_AGENT_API_VERSION', parameters('azureAiAgentApiVersion'), 'SOLUTION_NAME', parameters('solutionName'), 'USE_CHAT_HISTORY_ENABLED', 'True', 'AZURE_COSMOSDB_ACCOUNT', reference('cosmosDB').outputs.name.value, 'AZURE_COSMOSDB_ACCOUNT_KEY', '', 'AZURE_COSMOSDB_CONVERSATIONS_CONTAINER', variables('cosmosDBcollectionName'), 'AZURE_COSMOSDB_DATABASE', variables('cosmosDBDatabaseName'), 'azureCosmosDbEnableFeedback', variables('azureCosmosDbEnableFeedback'), 'UWSGI_PROCESSES', '2', 'UWSGI_THREADS', '2', 'APP_ENV', variables('appEnvironment'), 'AZURE_CLIENT_ID', reference('userAssignedIdentity').outputs.clientId.value), 'applicationInsightResourceId', if(parameters('enableMonitoring'), reference('applicationInsights').outputs.resourceId.value, null()))), if(parameters('enableMonitoring'), createArray(createObject('name', 'logs', 'properties', createObject())), createArray()))]" + "value": "[concat(createArray(createObject('name', 'appsettings', 'properties', createObject('SCM_DO_BUILD_DURING_DEPLOYMENT', 'true', 'DOCKER_REGISTRY_SERVER_URL', format('https://{0}.azurecr.io', parameters('acrName')), 'AUTH_ENABLED', 'false', 'AZURE_SEARCH_SERVICE', reference('aiSearch').outputs.name.value, 'AZURE_SEARCH_INDEX', variables('azureSearchIndex'), 'AZURE_SEARCH_USE_SEMANTIC_SEARCH', variables('azureSearchUseSemanticSearch'), 'AZURE_SEARCH_SEMANTIC_SEARCH_CONFIG', variables('azureSearchSemanticSearchConfig'), 'AZURE_SEARCH_INDEX_IS_PRECHUNKED', 'True', 'AZURE_SEARCH_TOP_K', '5', 'AZURE_SEARCH_ENABLE_IN_DOMAIN', variables('azureSearchEnableInDomain'), 'AZURE_SEARCH_CONTENT_COLUMNS', variables('azureSearchContentColumns'), 'AZURE_SEARCH_FILENAME_COLUMN', variables('azureSearchUrlColumn'), 'AZURE_SEARCH_TITLE_COLUMN', '', 'AZURE_SEARCH_URL_COLUMN', '', 'AZURE_SEARCH_QUERY_TYPE', variables('azureSearchQueryType'), 'AZURE_SEARCH_VECTOR_COLUMNS', variables('azureSearchVectorFields'), 'AZURE_SEARCH_PERMITTED_GROUPS_COLUMN', '', 'AZURE_SEARCH_STRICTNESS', '3', 'AZURE_SEARCH_CONNECTION_NAME', variables('aiSearchConnectionName'), 'AZURE_OPENAI_API_VERSION', parameters('azureOpenaiAPIVersion'), 'AZURE_OPENAI_MODEL', parameters('gptModelName'), 'AZURE_OPENAI_ENDPOINT', format('https://{0}.openai.azure.com/', variables('aiFoundryAiServicesResourceName')), 'AZURE_OPENAI_RESOURCE', variables('aiFoundryAiServicesResourceName'), 'AZURE_OPENAI_PREVIEW_API_VERSION', parameters('azureOpenaiAPIVersion'), 'AZURE_OPENAI_GENERATE_SECTION_CONTENT_PROMPT', variables('azureOpenAiGenerateSectionContentPrompt'), 'AZURE_OPENAI_TEMPLATE_SYSTEM_MESSAGE', variables('azureOpenAiTemplateSystemMessage'), 'AZURE_OPENAI_TITLE_PROMPT', variables('azureOpenAiTitlePrompt'), 'AZURE_OPENAI_SYSTEM_MESSAGE', variables('azureOpenAISystemMessage'), 'AZURE_AI_AGENT_ENDPOINT', if(variables('useExistingAiFoundryAiProject'), format('https://{0}.services.ai.azure.com/api/projects/{1}', variables('aiFoundryAiServicesResourceName'), variables('aiFoundryAiProjectResourceName')), reference('aiFoundryAiServicesProject').outputs.apiEndpoint.value), 'AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME', parameters('gptModelName'), 'AZURE_AI_AGENT_API_VERSION', parameters('azureAiAgentApiVersion'), 'SOLUTION_NAME', parameters('solutionName'), 'USE_CHAT_HISTORY_ENABLED', 'True', 'AZURE_COSMOSDB_ACCOUNT', reference('cosmosDB').outputs.name.value, 'AZURE_COSMOSDB_ACCOUNT_KEY', '', 'AZURE_COSMOSDB_CONVERSATIONS_CONTAINER', variables('cosmosDBcollectionName'), 'AZURE_COSMOSDB_DATABASE', variables('cosmosDBDatabaseName'), 'azureCosmosDbEnableFeedback', variables('azureCosmosDbEnableFeedback'), 'UWSGI_PROCESSES', '2', 'UWSGI_THREADS', '2', 'APP_ENV', variables('appEnvironment'), 'AZURE_CLIENT_ID', reference('userAssignedIdentity').outputs.clientId.value, 'AZURE_BASIC_LOGGING_LEVEL', 'INFO', 'AZURE_PACKAGE_LOGGING_LEVEL', 'WARNING', 'AZURE_LOGGING_PACKAGES', ''), 'applicationInsightResourceId', if(parameters('enableMonitoring'), reference('applicationInsights').outputs.resourceId.value, null()))), if(parameters('enableMonitoring'), createArray(createObject('name', 'logs', 'properties', createObject())), createArray()))]" }, "enableMonitoring": { "value": "[parameters('enableMonitoring')]" @@ -39649,8 +39654,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.38.33.27573", - "templateHash": "6605577820404885863" + "version": "0.37.4.10188", + "templateHash": "4085174230724704576" } }, "definitions": { @@ -40635,7 +40640,7 @@ "count": "[length(coalesce(parameters('configs'), createArray()))]" }, "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", + "apiVersion": "2022-09-01", "name": "[format('{0}-Site-Config-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { @@ -40673,8 +40678,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.38.33.27573", - "templateHash": "6347509742103743399" + "version": "0.37.4.10188", + "templateHash": "3088317872832633980" }, "name": "Site App Settings", "description": "This module deploys a Site App Setting." @@ -40829,7 +40834,7 @@ "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" }, "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", + "apiVersion": "2022-09-01", "name": "[format('{0}-app-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", diff --git a/infra/main_custom.bicep b/infra/main_custom.bicep index 15764f5ad..9c71835f8 100644 --- a/infra/main_custom.bicep +++ b/infra/main_custom.bicep @@ -1201,6 +1201,9 @@ module webSite 'modules/web-sites.bicep' = { UWSGI_THREADS: '2' APP_ENV: appEnvironment AZURE_CLIENT_ID: userAssignedIdentity.outputs.clientId + AZURE_BASIC_LOGGING_LEVEL: 'INFO' + AZURE_PACKAGE_LOGGING_LEVEL: 'WARNING' + AZURE_LOGGING_PACKAGES: '' } // WAF aligned configuration for Monitoring applicationInsightResourceId: enableMonitoring ? applicationInsights!.outputs.resourceId : null diff --git a/src/.env.sample b/src/.env.sample index 988f967ee..72cef0f31 100644 --- a/src/.env.sample +++ b/src/.env.sample @@ -1,5 +1,11 @@ -# Chat -DEBUG=True +# Basic application logging (default: INFO level) +AZURE_BASIC_LOGGING_LEVEL=INFO +# Azure package logging (default: WARNING level to suppress INFO) +AZURE_PACKAGE_LOGGING_LEVEL=WARNING +# Comma-separated list of specific logger names to configure (default: empty - no custom loggers) +# Example: AZURE_LOGGING_PACKAGES=azure.identity.aio._internal,azure.monitor.opentelemetry.exporter.export._base +AZURE_LOGGING_PACKAGES= + AZURE_AI_AGENT_API_VERSION= AZURE_AI_AGENT_ENDPOINT= AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME= diff --git a/src/app.py b/src/app.py index 69f1032fb..a7bf5ffea 100644 --- a/src/app.py +++ b/src/app.py @@ -20,7 +20,7 @@ MINIMUM_SUPPORTED_AZURE_OPENAI_PREVIEW_API_VERSION, app_settings) from backend.utils import (ChatType, format_as_ndjson, format_non_streaming_response, - format_stream_response) + format_stream_response, configure_logging) from event_utils import track_event_if_configured from azure.monitor.opentelemetry import configure_azure_monitor from opentelemetry import trace @@ -40,6 +40,9 @@ bp = Blueprint("routes", __name__, static_folder="static", template_folder="static") +# Configure logging based on environment variables +configure_logging(app_settings.logging) + # Check if the Application Insights Instrumentation Key is set in the environment variables instrumentation_key = os.getenv("APPLICATIONINSIGHTS_CONNECTION_STRING") if instrumentation_key: @@ -50,20 +53,6 @@ # Log a warning if the Instrumentation Key is not found logging.warning("No Application Insights Instrumentation Key found. Skipping configuration") -# Configure logging -logging.basicConfig(level=logging.INFO) - -# Suppress INFO logs from 'azure.core.pipeline.policies.http_logging_policy' -logging.getLogger("azure.core.pipeline.policies.http_logging_policy").setLevel( - logging.WARNING -) -logging.getLogger("azure.identity.aio._internal").setLevel(logging.WARNING) - -# Suppress info logs from OpenTelemetry exporter -logging.getLogger("azure.monitor.opentelemetry.exporter.export._base").setLevel( - logging.WARNING -) - def create_app(): app = Quart(__name__) @@ -115,10 +104,7 @@ async def assets(path): return await send_from_directory("static/assets", path) -# Debug settings -DEBUG = os.environ.get("DEBUG", "false") -if DEBUG.lower() == "true": - logging.basicConfig(level=logging.DEBUG) +# Debug settings are now handled by the logging configuration above USER_AGENT = "GitHubSampleWebApp/AsyncAzureOpenAI/1.0.0" diff --git a/src/backend/settings.py b/src/backend/settings.py index c70618dc6..206a7d3b7 100644 --- a/src/backend/settings.py +++ b/src/backend/settings.py @@ -34,6 +34,31 @@ class _UiSettings(BaseSettings): show_share_button: bool = False +class _LoggingSettings(BaseSettings): + model_config = SettingsConfigDict( + env_prefix="AZURE_", env_file=DOTENV_PATH, extra="ignore", env_ignore_empty=True + ) + + basic_logging_level: Literal["DEBUG", "INFO", "WARNING", "ERROR"] = "INFO" + package_logging_level: Literal["DEBUG", "INFO", "WARNING", "ERROR"] = "WARNING" + logging_packages: Optional[List[str]] = [] + + @field_validator("logging_packages", mode="before") + @classmethod + def split_logging_packages(cls, packages) -> Optional[List[str]]: + if isinstance(packages, str) and len(packages.strip()) > 0: + return [pkg.strip() for pkg in packages.split(",") if pkg.strip()] + return None + + def get_basic_log_level(self) -> int: + """Convert string log level to logging constant""" + return getattr(logging, self.basic_logging_level.upper()) + + def get_package_log_level(self) -> int: + """Convert string package log level to logging constant""" + return getattr(logging, self.package_logging_level.upper()) + + class _ChatHistorySettings(BaseSettings): model_config = SettingsConfigDict( env_prefix="AZURE_COSMOSDB_", @@ -367,6 +392,7 @@ class _AppSettings(BaseModel): azure_ai: _AzureAISettings = _AzureAISettings() search: _SearchCommonSettings = _SearchCommonSettings() ui: Optional[_UiSettings] = _UiSettings() + logging: _LoggingSettings = _LoggingSettings() # Constructed properties chat_history: Optional[_ChatHistorySettings] = None diff --git a/src/backend/utils.py b/src/backend/utils.py index 6822247b8..7432b5b4a 100644 --- a/src/backend/utils.py +++ b/src/backend/utils.py @@ -8,10 +8,6 @@ import uuid import time -DEBUG = os.environ.get("DEBUG", "false") -if DEBUG.lower() == "true": - logging.basicConfig(level=logging.DEBUG) - AZURE_SEARCH_PERMITTED_GROUPS_COLUMN = os.environ.get( "AZURE_SEARCH_PERMITTED_GROUPS_COLUMN" ) @@ -153,3 +149,24 @@ def comma_separated_string_to_list(s: str) -> List[str]: Split comma-separated values into a list. """ return s.strip().replace(" ", "").split(",") + + +def configure_logging(logging_settings): + """ + Configure logging based on the provided logging settings. + + Args: + logging_settings: Instance of _LoggingSettings containing logging configuration + """ + # Configure basic logging + logging.basicConfig( + level=logging_settings.get_basic_log_level(), + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', + force=True # Override any existing configuration + ) + + azure_log_level = logging_settings.get_package_log_level() + for logger_name in logging_settings.logging_packages or []: + logging.getLogger(logger_name).setLevel(azure_log_level) + + logging.info(f"Logging configured - Basic: {logging_settings.basic_logging_level}, Azure packages: {logging_settings.package_logging_level}, Packages: {logging_settings.logging_packages}")