KQL Cheatsheet - Azure Container Apps Logs¶
All queries target ContainerAppConsoleLogs_CL or ContainerAppSystemLogs_CL via the Azure Monitor
datasource in Grafana Explore. Select Azure Log Analytics query type and point to the
Log Analytics workspace resource for the target region.
Workspaces¶
| Region | Workspace | Apps |
|---|---|---|
| Italy North | law-stacksync-prod-italynorth |
backend-stacksync-prod, connectors-prod, connectors-prod-opt-conc, connectors-prod-16gb, connectors-prod-32gb, event-forward-prod, workflow-execution-engine-prod, workflows-events-receiver-prod |
| North Central US | law-stacksync-prod-northcentralus |
backend-stacksync-prod, connectors-prod, connectors-prod-opt-conc, connectors-prod-16gb, connectors-prod-32gb, event-forward-prod, workflow-execution-engine-prod, workflows-events-receiver-prod |
Replace backend-stacksync-prod with any container app name in the queries below.
Access Logs (gunicorn)¶
All requests with latency¶
ContainerAppConsoleLogs_CL
| where ContainerAppName_s == 'backend-stacksync-prod'
| where Log_s startswith 'access_log:'
| extend DurationMs = todouble(extract(@'dur=(\d+)', 1, Log_s)) / 1000.0
| extend StatusCode = toint(extract(@'status=(\d+)', 1, Log_s))
| extend Method = extract(@'method=(\w+)', 1, Log_s)
| extend Path = extract(@'path=(\S+)', 1, Log_s)
| project TimeGenerated, Method, Path, StatusCode, DurationMs
| order by TimeGenerated desc
Slow requests (> 1s)¶
ContainerAppConsoleLogs_CL
| where ContainerAppName_s == 'backend-stacksync-prod'
| where Log_s startswith 'access_log:'
| extend DurationMs = todouble(extract(@'dur=(\d+)', 1, Log_s)) / 1000.0
| extend StatusCode = toint(extract(@'status=(\d+)', 1, Log_s))
| extend Path = extract(@'path=(\S+)', 1, Log_s)
| where DurationMs > 1000
| project TimeGenerated, Path, StatusCode, DurationMs
| order by DurationMs desc
5xx errors¶
ContainerAppConsoleLogs_CL
| where ContainerAppName_s == 'backend-stacksync-prod'
| where Log_s startswith 'access_log:'
| extend StatusCode = toint(extract(@'status=(\d+)', 1, Log_s))
| extend Path = extract(@'path=(\S+)', 1, Log_s)
| where StatusCode >= 500
| project TimeGenerated, Path, StatusCode, Log_s
| order by TimeGenerated desc
P50/P95/P99 latency (5-min bins)¶
ContainerAppConsoleLogs_CL
| where ContainerAppName_s == 'backend-stacksync-prod'
| where Log_s startswith 'access_log:'
| extend DurationMs = todouble(extract(@'dur=(\d+)', 1, Log_s)) / 1000.0
| where isnotnull(DurationMs)
| summarize
p50 = percentile(DurationMs, 50),
p95 = percentile(DurationMs, 95),
p99 = percentile(DurationMs, 99)
by bin(TimeGenerated, 5m)
| order by TimeGenerated desc
Error rate per 5 min¶
ContainerAppConsoleLogs_CL
| where ContainerAppName_s == 'backend-stacksync-prod'
| where Log_s startswith 'access_log:'
| extend StatusCode = toint(extract(@'status=(\d+)', 1, Log_s))
| summarize
Total = count(),
Errors5xx = countif(StatusCode >= 500),
ErrorRate = round(100.0 * countif(StatusCode >= 500) / count(), 2)
by bin(TimeGenerated, 5m)
| order by TimeGenerated desc
Top endpoints by volume¶
ContainerAppConsoleLogs_CL
| where ContainerAppName_s == 'backend-stacksync-prod'
| where Log_s startswith 'access_log:'
| extend Path = extract(@'path=(\S+)', 1, Log_s)
| extend NormPath = replace_regex(Path, @'[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|\b\d{4,}\b', '{id}')
| summarize Count = count() by NormPath
| order by Count desc
| take 20
Latency percentiles by endpoint¶
ContainerAppConsoleLogs_CL
| where ContainerAppName_s == 'backend-stacksync-prod'
| where Log_s startswith 'access_log:'
| extend DurationMs = todouble(extract(@'dur=(\d+)', 1, Log_s)) / 1000.0
| extend Method = extract(@'method=(\w+)', 1, Log_s)
| extend Path = extract(@'path=(\S+)', 1, Log_s)
| extend NormPath = replace_regex(Path, @'[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|\b\d{4,}\b', '{id}')
| where isnotnull(DurationMs)
| summarize
p50 = percentile(DurationMs, 50),
p95 = percentile(DurationMs, 95),
p99 = percentile(DurationMs, 99),
Count = count()
by Method, NormPath
| order by Count desc
| take 30
Application Logs¶
Python exceptions / tracebacks¶
ContainerAppConsoleLogs_CL
| where ContainerAppName_s == 'backend-stacksync-prod'
| where Log_s startswith 'Traceback' or Log_s startswith 'TypeError' or Log_s startswith 'Error'
| project TimeGenerated, Log_s
| order by TimeGenerated desc
App logs only (filter out noise)¶
Filters out urllib3 outgoing request logs and access logs to show only application-level logs.
ContainerAppConsoleLogs_CL
| where ContainerAppName_s == 'backend-stacksync-prod'
| where Log_s !startswith 'access_log:'
| where Log_s !startswith 'https://'
| where Log_s !startswith 'Starting new HTTPS'
| project TimeGenerated, Stream_s, Log_s
| order by TimeGenerated desc
| take 200
JSON structured app logs¶
ContainerAppConsoleLogs_CL
| where ContainerAppName_s == 'backend-stacksync-prod'
| where Log_s startswith '{'
| extend parsed = parse_json(Log_s)
| extend LogType = tostring(parsed.type), Msg = tostring(parsed.msg)
| where isnotempty(LogType)
| project TimeGenerated, LogType, Msg
| order by TimeGenerated desc
| take 100
System Logs¶
Scaling events¶
ContainerAppSystemLogs_CL
| where ContainerAppName_s == 'backend-stacksync-prod'
| where EventSource_s == 'Scaling'
| project TimeGenerated, Log_s, RevisionName_s
| order by TimeGenerated desc
KEDA scaler events¶
ContainerAppSystemLogs_CL
| where ContainerAppName_s == 'backend-stacksync-prod'
| where EventSource_s == 'KEDA'
| project TimeGenerated, Reason_s, Log_s
| order by TimeGenerated desc
Container restarts / crashes¶
ContainerAppSystemLogs_CL
| where ContainerAppName_s == 'backend-stacksync-prod'
| where Reason_s in ('BackOff', 'CrashLoopBackOff', 'Killing', 'Unhealthy', 'Failed')
| project TimeGenerated, Reason_s, Log_s, ReplicaName_s
| order by TimeGenerated desc
Health probe failures¶
ContainerAppSystemLogs_CL
| where ContainerAppName_s == 'backend-stacksync-prod'
| where Reason_s == 'ProbeFailed'
| project TimeGenerated, Log_s, ReplicaName_s
| order by TimeGenerated desc
Container terminations¶
ContainerAppSystemLogs_CL
| where ContainerAppName_s == 'backend-stacksync-prod'
| where Reason_s in ('ContainerTerminated', 'ProcessExited', 'StoppingContainer')
| project TimeGenerated, Reason_s, Log_s, ReplicaName_s
| order by TimeGenerated desc
Replica failures¶
ContainerAppSystemLogs_CL
| where ContainerAppName_s == 'backend-stacksync-prod'
| where Reason_s in ('AssigningReplicaFailed', 'ReplicaUnhealthy', 'ContainerBackOff', 'Error', 'ContainerAppFailure')
| project TimeGenerated, Reason_s, Log_s, ReplicaName_s
| order by TimeGenerated desc
Deployment / revision events¶
ContainerAppSystemLogs_CL
| where ContainerAppName_s == 'backend-stacksync-prod'
| where Reason_s in ('RevisionCreation', 'RevisionReady', 'RollingRevisionCompleted', 'RevisionUpdate')
| project TimeGenerated, Reason_s, RevisionName_s, Log_s
| order by TimeGenerated desc
Cross-App Queries¶
All apps - 5xx count last 1h¶
ContainerAppConsoleLogs_CL
| where Log_s startswith 'access_log:'
| extend StatusCode = toint(extract(@'status=(\d+)', 1, Log_s))
| where StatusCode >= 500
| summarize Count = count() by ContainerAppName_s
| order by Count desc
All apps - slowest requests last 1h¶
ContainerAppConsoleLogs_CL
| where Log_s startswith 'access_log:'
| extend DurationMs = todouble(extract(@'dur=(\d+)', 1, Log_s)) / 1000.0
| extend Path = extract(@'path=(\S+)', 1, Log_s)
| where DurationMs > 5000
| project TimeGenerated, ContainerAppName_s, Path, DurationMs
| order by DurationMs desc
| take 50
All apps - request volume¶
ContainerAppConsoleLogs_CL
| where Log_s startswith 'access_log:'
| summarize RequestCount = count() by ContainerAppName_s
| order by RequestCount desc
Notes¶
durin access logs is in microseconds (divide by 1000 for ms)- Access logs are emitted via
GUNICORN_CMD_ARGSenv var set on all prod container apps - Log format:
access_log:dur=<us>,status=<code>,method=<METHOD>,path=<path> - Path normalization:
replace_regex(Path, @'[0-9a-f]{8}-...-[0-9a-f]{12}|\b\d{4,}\b', '{id}')collapses UUIDs and numeric IDs into{id} - Adjust
TimeGeneratedfilters or Grafana time picker to control the time range - Each region has its own workspace — run cross-region comparisons by querying both workspaces separately