04 - Logging, Monitoring, and Observability¶
This tutorial step shows how to inspect console logs, query Log Analytics, and add Application Insights-based observability for production operations.
Infrastructure Context
Service: Container Apps (Consumption) | Network: VNet integrated | VNet: ✅
This tutorial assumes a production-ready Container Apps deployment with a custom VNet, ACR with managed identity pull, and private endpoints for backend services.
flowchart TD
INET[Internet] -->|HTTPS| CA["Container App\nConsumption\nLinux Node 18 LTS"]
subgraph VNET["VNet 10.0.0.0/16"]
subgraph ENV_SUB["Environment Subnet 10.0.0.0/23\nDelegation: Microsoft.App/environments"]
CAE[Container Apps Environment]
CA
end
subgraph PE_SUB["Private Endpoint Subnet 10.0.2.0/24"]
PE_ACR[PE: ACR]
PE_KV[PE: Key Vault]
PE_ST[PE: Storage]
end
end
PE_ACR --> ACR[Azure Container Registry]
PE_KV --> KV[Key Vault]
PE_ST --> ST[Storage Account]
subgraph DNS[Private DNS Zones]
DNS_ACR[privatelink.azurecr.io]
DNS_KV[privatelink.vaultcore.azure.net]
DNS_ST[privatelink.blob.core.windows.net]
end
PE_ACR -.-> DNS_ACR
PE_KV -.-> DNS_KV
PE_ST -.-> DNS_ST
CA -.->|System-Assigned MI| ENTRA[Microsoft Entra ID]
CAE --> LOG[Log Analytics]
CA --> AI[Application Insights]
style CA fill:#107c10,color:#fff
style VNET fill:#E8F5E9,stroke:#4CAF50
style DNS fill:#E3F2FD How Observability Works in Container Apps¶
flowchart LR
APP[App container stdout/stderr] --> CONSOLE[Console logs]
DAPR[Dapr sidecar stdout/stderr] --> CONSOLE
PLATFORM[Platform/revision/auth events] --> SYSTEM[System logs]
CONSOLE --> LAW[Log Analytics workspace]
SYSTEM --> LAW
OTEL[App instrumentation<br/>Application Insights SDK] --> AI[Application Insights]
AZMON[Azure Monitor] --> METRICS[Metrics: requests, CPU, memory, replicas] Prerequisites¶
- Completed 03 - Configuration, Secrets, and Dapr
- Log Analytics connected to your Container Apps environment
Step-by-step¶
-
Set standard variables
-
Stream console logs
Expected output
Note
Use Ctrl+C to stop following logs.
-
Check system logs for startup or image issues
-
Query logs via CLI (recommended for automation)
Get your Log Analytics workspace ID and run KQL queries directly from the command line:
# Get the workspace ID WORKSPACE_ID=$(az monitor log-analytics workspace list \ --resource-group "$RG" \ --query "[0].customerId" \ --output tsv) # Query console logs (use your actual app name from $APP_NAME) az monitor log-analytics query \ --workspace $WORKSPACE_ID \ --analytics-query "ContainerAppConsoleLogs_CL | where ContainerAppName_s == '$APP_NAME' | project TimeGenerated, ContainerAppName_s, Log_s | take 5" \ --output tableExpected output
ContainerAppName_s Log_s TimeGenerated -------------------- --------------------------------------------------------------------------------------------- ---------------------------- <your-app-name> {"timestamp":"2026-04-04T16:10:50.376Z","level":"INFO","message":"Server started on port 8000"} 2026-04-04T16:10:51.723Z <your-app-name> {"timestamp":"2026-04-04T16:11:58.005Z","level":"INFO","method":"GET","path":"/health",...} 2026-04-04T16:11:58.474Z -
Query for errors via CLI
az monitor log-analytics query \ --workspace $WORKSPACE_ID \ --analytics-query "ContainerAppConsoleLogs_CL | where ContainerAppName_s == '$APP_NAME' | where Log_s has_any ('error', 'exception', 'failed') | project TimeGenerated, Log_s | take 10" \ --output tableExpected output
If no errors exist, the query returns an empty result set:
If errors exist, they appear with timestamps:
-
Enable Application Insights (OpenTelemetry)
The reference app includes the
applicationinsightsSDK. To enable it, provide the connection string:# Get connection string from your App Insights resource CONNECTION_STRING="InstrumentationKey=...;IngestionEndpoint=..." az containerapp update \ --name "$APP_NAME" \ --resource-group "$RG" \ --set-env-vars "APPLICATIONINSIGHTS_CONNECTION_STRING=$CONNECTION_STRING"The app will automatically start collecting: - HTTP request metrics (latency, throughput) - Exception traces - Console log redirection to App Insights - Dependency tracking (outbound HTTP calls)
Node.js Structured Logging¶
The reference app uses a custom middleware to emit JSON logs. This ensures logs are easily searchable in Log Analytics.
// src/middleware/logging.js
const jsonLogger = (req, res, next) => {
res.on('finish', () => {
console.log(JSON.stringify({
timestamp: new Date().toISOString(),
level: 'INFO',
method: req.method,
url: req.url,
status: res.statusCode
}));
});
next();
};
Advanced Topics¶
- Use the
winstonorpinolibraries for more advanced logging features like log levels and multiple transports. - Configure custom metrics in Application Insights to track business-specific KPIs.
- Use Service Map in Application Insights to visualize dependencies between your microservices.