Diagnostic Settings Missing¶
Use this playbook when no ContainerAppConsoleLogs_CL or ContainerAppSystemLogs_CL rows appear in Log Analytics for any app in a Container Apps environment, and the environment was provisioned via IaC (Bicep, ARM, or Terraform) or via a Portal flow that did not configure the log destination. The primary scenario is an environment whose properties.appLogsConfiguration was omitted at provisioning time and now reads destination: null on the live resource. In that state, environment-level log routing to Log Analytics is missing for every app in the environment. A variant scenario where the environment is configured for destination: azure-monitor but the downstream Microsoft.Insights/diagnosticSettings resource was never created is covered at the end.
Symptom¶
az containerapp env show --query "properties.appLogsConfiguration"returns{"destination": null, "logAnalyticsConfiguration": null}on the environment that should be writing to Log Analytics.- KQL queries against
ContainerAppConsoleLogs_CLandContainerAppSystemLogs_CLreturnBadArgumentError: SEM0100 'where' operator: Failed to resolve table— the tables never materialized in the workspace because no log data has ever been written to them. - A newly created environment or a newly created app inside an existing environment shows no logs after traffic, restarts, or
RevisionReadyevents, and the silence is uniform across every app in the environment (not isolated to one app). - The Log Analytics workspace exists and is otherwise healthy (other resources in the same workspace continue to ingest), but no Container Apps tables appear in the workspace schema.
Possible Causes¶
- The Bicep, ARM, or Terraform module that creates the environment omitted the
appLogsConfigurationproperty entirely, so the live environment lands atdestination: null. - A subsequent
az deployment group createreverted a live fix back todestination: nullbecause the IaC declaration was never updated to match the manually-applied fix. - The environment was created via Portal but the operator skipped the log destination step in the creation wizard.
- The environment is configured for
destination: azure-monitorbut the downstreamMicrosoft.Insights/diagnosticSettingsresource was never created on the environment resource (variant scenario — see the dedicated section below). - The environment is configured for a different destination entirely (
azure-blob-storage, no destination, etc.) and the team expected Log Analytics ingestion by default.
Diagnosis Steps¶
flowchart TD
A[Notice empty Log Analytics tables for the environment] --> B[Read environment appLogsConfiguration]
B --> C{destination value?}
C -->|null| D[Primary scenario: env was provisioned without log routing]
C -->|log-analytics| E[Different cause - check workspace IDs and ingestion lag]
C -->|azure-monitor| F[Variant scenario: check Microsoft.Insights/diagnosticSettings on env resource]
C -->|other| G[Use the playbook for that destination]
D --> H[Apply env-level fix: az containerapp env update --logs-destination log-analytics ...]
F --> I[Apply diagnostic-setting fix: az monitor diagnostic-settings create --resource ENV_RESOURCE_ID ...]
H --> J[Force new revision to emit fresh RevisionReady event]
I --> J
J --> K[Wait 5 minutes for log ingestion]
K --> L{Rows present in Log Analytics?}
L -->|Yes| M[Routing is restored]
L -->|No| N[Escalate - check workspace customerId mismatch or platform issue] -
Read the environment's
appLogsConfiguration— this is the single most important check.az containerapp env show \ --subscription "$SUBSCRIPTION_ID" \ --resource-group "$RG" \ --name "$ACA_ENV_NAME" \ --query "properties.appLogsConfiguration" \ --output jsonCommand Why it is used az containerapp env show --query "properties.appLogsConfiguration" --output jsonReturns the full log destination configuration in one call. The shape of the response tells you which branch of the playbook to follow: {"destination": null, ...}is the primary scenario;{"destination": "azure-monitor", ...}is the variant scenario;{"destination": "log-analytics", "logAnalyticsConfiguration": {"customerId": "..."}}means the destination is configured and the silence is caused by something else (workspace IDs, ingestion lag, or a per-app issue). -
If
destinationisnull, you are in the primary scenario. Capture the workspace resource ID and customer ID you will need for the fix.az monitor log-analytics workspace show \ --subscription "$SUBSCRIPTION_ID" \ --resource-group "$RG" \ --workspace-name "$WORKSPACE_NAME" \ --query "{id:id, customerId:customerId}" \ --output jsonCommand Why it is used az monitor log-analytics workspace show --query "{id:id, customerId:customerId}" --output jsonReturns both the ARM resource ID (used by az monitor diagnostic-settingsfor the variant scenario) and the workspace customer ID (used byaz containerapp env update --logs-workspace-idfor the primary scenario). -
If
destinationisazure-monitor, you are in the variant scenario. List diagnostic settings on the environment resource.ENV_RESOURCE_ID=$(az containerapp env show \ --subscription "$SUBSCRIPTION_ID" \ --resource-group "$RG" \ --name "$ACA_ENV_NAME" \ --query "id" \ --output tsv) az monitor diagnostic-settings list \ --resource "$ENV_RESOURCE_ID" \ --output jsonCommand Why it is used az containerapp env show --query "id" --output tsvReturns the ARM resource ID of the managed environment so it can be passed to az monitor diagnostic-settings.az monitor diagnostic-settings list --resource "$ENV_RESOURCE_ID" --output jsonLists every diagnostic setting attached to the environment resource. An empty array confirms the variant scenario: the destination is azure-monitorbut no downstream routing exists. -
Confirm the silence is workspace-wide by running the canonical KQL on both tables.
let AppName = "ca-myapp"; ContainerAppConsoleLogs_CL | where ContainerAppName_s == AppName | where TimeGenerated > ago(30m) | project TimeGenerated, RevisionName_s, Log_s | order by TimeGenerated desclet AppName = "ca-myapp"; ContainerAppSystemLogs_CL | where ContainerAppName_s == AppName | where TimeGenerated > ago(30m) | project TimeGenerated, RevisionName_s, Reason_s, Log_s | order by TimeGenerated descA
BadArgumentError: SEM0100 'where' operator: Failed to resolve tableresponse on both queries is the strongest signal that the tables never materialized in this workspace, which is consistent with the primary scenario where the environment never had a log destination configured. A "0 rows" response on tables that exist means a different cause (workspace mismatch, app filter mismatch, ingestion lag).
Resolution¶
Primary scenario — environment with destination: null¶
-
Update the environment to set the Log Analytics destination. The shared key is required and must be passed at command-time; do not persist it.
WORKSPACE_CUSTOMER_ID=$(az monitor log-analytics workspace show \ --subscription "$SUBSCRIPTION_ID" \ --resource-group "$RG" \ --workspace-name "$WORKSPACE_NAME" \ --query "customerId" \ --output tsv) WORKSPACE_SHARED_KEY=$(az monitor log-analytics workspace get-shared-keys \ --subscription "$SUBSCRIPTION_ID" \ --resource-group "$RG" \ --workspace-name "$WORKSPACE_NAME" \ --query "primarySharedKey" \ --output tsv) az containerapp env update \ --subscription "$SUBSCRIPTION_ID" \ --resource-group "$RG" \ --name "$ACA_ENV_NAME" \ --logs-destination log-analytics \ --logs-workspace-id "$WORKSPACE_CUSTOMER_ID" \ --logs-workspace-key "$WORKSPACE_SHARED_KEY" unset WORKSPACE_SHARED_KEYCommand Why it is used az monitor log-analytics workspace show --query "customerId" --output tsvReturns the workspace customer ID (a GUID), which is the value az containerapp env update --logs-workspace-idexpects. This is NOT the workspace ARM resource ID.az monitor log-analytics workspace get-shared-keys --query "primarySharedKey" --output tsvReturns the workspace shared key. This is a secret — read it into a shell variable at command-time and unsetit immediately afteraz containerapp env update. Never commit it to evidence files or paste it into chat.az containerapp env update --logs-destination log-analytics --logs-workspace-id <customerId> --logs-workspace-key <sharedKey>Sets the environment-level appLogsConfigurationto{"destination": "log-analytics", "logAnalyticsConfiguration": {"customerId": "..."}}on the live resource. This is the fix that restores ingestion for every app in the environment. -
Force a new revision so the platform emits a fresh
RevisionReadyevent after the destination was set.NONCE="$(date -u +%Y%m%dT%H%M%SZ)" az containerapp update \ --subscription "$SUBSCRIPTION_ID" \ --resource-group "$RG" \ --name "$APP_NAME" \ --set-env-vars "FIXAPPLIED=$NONCE"Command Why it is used az containerapp update --set-env-vars FIXAPPLIED=<nonce>Adds (or updates) an environment variable on the Container App. Any env var change invalidates the previous revision template hash and creates a new revision under activeRevisionsMode: Single. This is the cheapest way to guarantee the platform emits a freshRevisionReadyevent intoContainerAppSystemLogs_CLAFTER the environment was updated, so you have an unambiguous post-fix signal to query. -
Wait 5 minutes for ingestion, then re-run the KQL from step 4 of Diagnosis. Both
ContainerAppConsoleLogs_CLandContainerAppSystemLogs_CLshould now return rows. A row count of0on either table after the wait window means escalate: re-check the workspace customer ID, re-check that the new revision actually entered theRunningstate, and confirm the workspace is in the same tenant as the environment. -
Update the IaC that originally provisioned this environment (Bicep / ARM / Terraform) to include
appLogsConfiguration. If you skip this step, the nextaz deployment group createwill revert the live fix back todestination: null.
Variant scenario — environment with destination: azure-monitor and no diagnostic setting¶
If the environment is configured for azure-monitor routing, the environment itself does not write to Log Analytics — the downstream Microsoft.Insights/diagnosticSettings resource is what forwards events from Azure Monitor to a workspace. If that resource is missing, no logs arrive.
-
Create the diagnostic setting on the environment resource.
az monitor diagnostic-settings create \ --subscription "$SUBSCRIPTION_ID" \ --name "aca-observability" \ --resource "$ENV_RESOURCE_ID" \ --workspace "$WORKSPACE_RESOURCE_ID" \ --logs '[{"category":"ContainerAppConsoleLogs","enabled":true},{"category":"ContainerAppSystemLogs","enabled":true}]' \ --metrics '[{"category":"AllMetrics","enabled":true}]'Command Why it is used az monitor diagnostic-settings create --name "aca-observability" --resource "$ENV_RESOURCE_ID" --workspace "$WORKSPACE_RESOURCE_ID" --logs ... --metrics ...Creates the diagnostic setting on the environment ARM resource that forwards ContainerAppConsoleLogs,ContainerAppSystemLogs, and metrics from Azure Monitor to the target Log Analytics workspace.--workspaceexpects the full ARM resource ID of the workspace, not the customer ID. -
Generate a fresh request or revision event so a new signal is produced AFTER the diagnostic setting was created. Use the same
FIXAPPLIED=<nonce>env-var update pattern as the primary scenario. -
Wait 5 minutes for ingestion, then re-run the KQL. Rows should now arrive.
Prevention¶
-
Always declare
appLogsConfigurationin the IaC that creates the Container Apps environment. The Bicep snippet below is the minimum that prevents the primary scenario: -
After every new environment creation, run
az containerapp env show --query "properties.appLogsConfiguration"as a smoke test. The expected response is{"destination": "log-analytics", ...}or{"destination": "azure-monitor", ...}— never{"destination": null}. - After every new environment creation, run the canonical KQL on both
*_CLtables within 5-10 minutes of first traffic. If either table returnsFailed to resolve table, the environment was provisioned without a log destination. - Keep the workspace customer ID and the workspace ARM resource ID in deployment outputs so post-deployment validation is a one-liner.
- Document at the team level that the environment log destination must be configured correctly before environment-wide console and system log ingestion can work.
See Also¶
- Diagnostic Settings Missing Lab
- Log Analytics Ingestion Gap
- Observability Tracing Lab
- CrashLoop OOM and Resource Pressure