| name | azure-monitor |
| description | Use when working with Azure Monitor — azure Monitor metrics querying, Log
Analytics workspace management, alert rule configuration, action groups, and
diagnostic settings via Azure CLI.
|
| connection_type | azure |
| preload | false |
Azure Monitor Skill
Manage and analyze Azure Monitor resources using az monitor commands.
Discovery-First Rule
ALWAYS discover before acting. Never assume workspace names, alert rule names, metric names, or action group names.
az monitor log-analytics workspace list --output json \
--query "[].{name:name, rg:resourceGroup, sku:sku.name, retentionDays:retentionInDays, dailyCapGB:workspaceCapping.dailyQuotaGb}"
az monitor metrics alert list --output json \
--query "[].{name:name, rg:resourceGroup, severity:severity, enabled:enabled, targetResource:scopes[0]}"
Parallel Execution Requirement
ALL independent operations MUST run in parallel using background jobs (&) and wait.
for ws in $(echo "$workspaces" | jq -c '.[]'); do
{
name=$(echo "$ws" | jq -r '.name')
rg=$(echo "$ws" | jq -r '.rg')
az monitor log-analytics workspace show --workspace-name "$name" --resource-group "$rg" --output json
} &
done
wait
Helper Functions
run_log_query() {
local workspace="$1" query="$2" timespan="${3:-PT1H}"
az monitor log-analytics query --workspace "$workspace" --analytics-query "$query" --timespan "$timespan" --output json
}
list_metrics() {
local resource_id="$1"
az monitor metrics list-definitions --resource "$resource_id" --output json \
--query "[].{name:name.value, displayName:name.localizedValue, unit:unit, aggregations:supportedAggregationTypes}"
}
get_metrics() {
local resource_id="$1" metrics="$2" interval="${3:-PT1H}" aggregation="${4:-Average}"
az monitor metrics list --resource "$resource_id" --metric $metrics \
--interval "$interval" --aggregation $aggregation --output json
}
list_action_groups() {
local rg="$1"
az monitor action-group list --resource-group --output json \
--query
}
Common Operations
1. Workspace Overview and Usage
workspaces=$(az monitor log-analytics workspace list --output json --query "[].{name:name, rg:resourceGroup, id:customerId}")
for ws in $(echo "$workspaces" | jq -c '.[]'); do
{
name=$(echo "$ws" | jq -r '.name')
rg=$(echo "$ws" | jq -r '.rg')
ws_id=$(echo "$ws" | jq -r '.id')
az monitor log-analytics workspace show --workspace-name "$name" --resource-group "$rg" --output json \
--query "{name:name, sku:sku.name, retentionDays:retentionInDays, dailyCap:workspaceCapping.dailyQuotaGb, ingestionStatus:workspaceCapping.quotaNextResetTime}"
run_log_query "$ws_id" "Usage | where TimeGenerated > ago(24h) | summarize DataGB=sum(Quantity)/1024 by DataType | sort by DataGB desc | take 10" "P1D"
} &
done
wait
2. Alert Rules Audit
az monitor metrics alert list --output json \
--query "[].{name:name, severity:severity, enabled:enabled, condition:criteria.allOf[0].{metric:metricName,operator:operator,threshold:threshold}, actions:actions[].actionGroupId}"
az monitor scheduled-query list --output json \
--query "[].{name:name, severity:severity, enabled:enabled, evaluationFrequency:evaluationFrequency, windowSize:windowSize}"
az monitor activity-log alert list --output json \
--query "[].{name:name, enabled:enabled, scopes:scopes, condition:condition}"
3. Log Analytics Queries
run_log_query "$WORKSPACE_ID" "union withsource=TableName * | where TimeGenerated > ago(1h) | where Level == 'Error' or severityLevel >= 3 | summarize count() by TableName | sort by count_ desc"
run_log_query "$WORKSPACE_ID" "Heartbeat | summarize LastHeartbeat=max(TimeGenerated) by Computer | where LastHeartbeat < ago(15m)"
run_log_query "$WORKSPACE_ID" "Heartbeat | where TimeGenerated > ago(1h) | extend IngestionDelay=ingestion_time()-TimeGenerated | summarize avg(IngestionDelay), max(IngestionDelay) by bin(TimeGenerated, 5m)"
4. Diagnostic Settings Audit
az monitor diagnostic-settings list --resource "$RESOURCE_ID" --output json \
--query "[].{name:name, workspace:workspaceId, storageAccount:storageAccountId, eventHub:eventHubAuthorizationRuleId, logs:logs[].{category:category, enabled:enabled, retention:retentionPolicy.days}, metrics:metrics[].{category:category, enabled:enabled}}"
5. Action Group Configuration
az monitor action-group list --output json \
--query "[].{name:name, rg:resourceGroup, enabled:enabled, email:emailReceivers[].{name:name,address:emailAddress}, sms:smsReceivers[].{name:name,phone:phoneNumber}, webhook:webhookReceivers[].{name:name,uri:serviceUri}, logicApp:logicAppReceivers[].{name:name}, azureFunction:azureFunctionReceivers[].{name:name}}"
Output Format
Present results as a structured report:
Azure Monitor Report
════════════════════
Resources discovered: [count]
Resource Status Key Metric Issues
──────────────────────────────────────────────
[name] [ok/warn] [value] [findings]
Summary: [total] resources | [ok] healthy | [warn] warnings | [crit] critical
Action Items: [list of prioritized findings]
Target ≤50 lines of output. Use tables for multi-resource comparisons.
Anti-Hallucination Rules
- NEVER assume resource names — always discover via CLI/API in Phase 1 before referencing in Phase 2.
- NEVER fabricate metric names or dimensions — verify against the service documentation or
--help output.
- NEVER mix CLI commands between service versions — confirm which version/API you are targeting.
- ALWAYS use the discovery → verify → analyze chain — every resource referenced must have been discovered first.
- ALWAYS handle empty results gracefully — an empty response is valid data, not an error to retry.
Counter-Rationalizations
| Shortcut | Counter | Why |
|---|
| "I'll skip discovery and check known resources" | Always run Phase 1 discovery first | Resource names change, new resources appear — assumed names cause errors |
| "The user only asked for a quick check" | Follow the full discovery → analysis flow | Quick checks miss critical issues; structured analysis catches silent failures |
| "Default configuration is probably fine" | Audit configuration explicitly | Defaults often leave logging, security, and optimization features disabled |
| "Metrics aren't needed for this" | Always check relevant metrics when available | API/CLI responses show current state; metrics reveal trends and intermittent issues |
| "I don't have access to that" | Try the command and report the actual error | Assumed permission failures prevent useful investigation; actual errors are informative |
Common Pitfalls
- Metric namespaces: Different resource types expose different metrics. Always use
list-definitions to discover available metrics before querying.
- Log Analytics timespan format: Use ISO 8601 duration format (e.g.,
PT1H, P1D, P7D), not date ranges.
- Daily cap resets: When daily ingestion cap is hit, data is dropped until the next reset time. Check
quotaNextResetTime.
- Alert action groups: An alert without action groups will fire but nobody gets notified. Always verify action group linkage.
- KQL vs SQL: Log Analytics uses Kusto Query Language (KQL), not SQL. Common mistakes include using
SELECT instead of project and GROUP BY instead of summarize.