Run one step, then check it
Read the step before copying. Bash commands belong in Git Bash on Windows or Azure Cloud Shell set to Bash; PowerShell uses different syntax. A JSON, YAML, Bicep or application-code example belongs in the named file, not directly at the terminal prompt. Follow any shell-specific instructions below.
Keep the same terminal open so earlier variables remain available. Copy one complete command block without the terminal's $ prompt. A backslash continues a command onto the next line. If Bash shows a lone >, it is waiting for the rest of a quote, command or file block. Finish the complete block; if the paste was incomplete, press Ctrl+C and copy it again. Do not paste the next step into an unfinished command.
A line such as RG="training-group" stores a value without printing it. Output captured with $(...) is also stored; a blank screen alone does not prove failure. A sleep deliberately waits, and -o none suppresses normal output. Wait for your normal prompt, then run the step's checkpoint. After an error, stop and keep the exact command and message; later steps cannot repair a missing resource. Never share passwords, access tokens or secret values in a screenshot.
Logs you cannot query are just storage
Azure records the subscription Activity Log automatically. It covers management events such as creating or deleting a resource group, not every operation inside a resource. This lab routes future Activity Log entries to Log Analytics, where KQL can query them. You will also configure a scheduled rule that looks for failed management operations. The rule and its email action need a separate delivery test before a team can depend on them.
By the end you will have a workspace collecting real data, a KQL query that reads back your own operations, and a scheduled-query alert rule with an action group behind it — a loop you can point at any workload later.
Monitoring is a question you have written down in advance.
You need an Azure subscription, Azure CLI access or Cloud Shell (Bash), and permission to create a workspace, action group, alert rule, and subscription-scoped diagnostic setting. Check your role at the subscription scope before starting; resource-group access alone may not be enough. Review current alert pricing because a free account does not guarantee a zero-cost run.
This page is the full lab; companion Bicep is in github.com/kloudcaptain/campux-labs. Azure includes the subscription Activity Log, but a scheduled log alert and action-group notifications can incur charges. Check current Azure Monitor pricing and set a small budget before creating the rule.
A workspace to collect into
Create a resource group and a Log Analytics workspace. The workspace is the pool everything queryable lands in.
Commands inside $(...) save their output in a variable. Check the printed identifier or the checkpoint before continuing.
# Windows/Git Bash: stop it mangling /subscriptions/... arguments (harmless on macOS/Linux)
export MSYS_NO_PATHCONV=1
RG="campux-lab-obs-rg"
az group create -n "$RG" -l eastus
az monitor log-analytics workspace create -g "$RG" -n campux-logs
WS_ID=$(az monitor log-analytics workspace show -g "$RG" -n campux-logs --query id -o tsv)
WS_GUID=$(az monitor log-analytics workspace show -g "$RG" -n campux-logs --query customerId -o tsv)
echo "workspace resource id: $WS_ID"
id (used to wire data in) and the customerId GUID (used to query). Empty for now; the next step gives it something to collect.Stream the Activity log in
A diagnostic setting at the subscription level routes the Activity log into your workspace. From now on, every management operation you run is recorded there.
Commands inside $(...) save their output in a variable. Check the printed identifier or the checkpoint before continuing.
SUB_ID=$(az account show --query id -o tsv)
az monitor diagnostic-settings subscription create \
--name campux-activity-to-logs \
--location eastus \
--subscription "$SUB_ID" \
--workspace "$WS_ID" \
--logs '[{"category":"Administrative","enabled":true},{"category":"Alert","enabled":true}]'
Now generate a little activity to be sure there is something to find — create and delete a throwaway resource group:
az group create -n campux-obs-ping -l eastus && az group delete -n campux-obs-ping --yes
AzureActivity.Ask a question in KQL
Query the AzureActivity table straight from the CLI. Read this KQL as a pipeline: take the table, keep the last hour, summarise a count per operation, sort by the busiest.
az monitor log-analytics query -w "$WS_GUID" --analytics-query ' AzureActivity | where TimeGenerated > ago(1h) | summarize count() by OperationNameValue, ActivityStatusValue | sort by count_ desc ' -o table
Turn a query into an alert
An alert is a KQL query Azure runs on a schedule, firing when it returns too many rows. First an action group — who gets told — then the rule itself, watching for failed operations.
Commands inside $(...) save their output in a variable. Check the printed identifier or the checkpoint before continuing.
# Enter an address you can check; the prompt avoids a fake recipient. read -r -p "Lab alert email: " ALERT_EMAIL test -n "$ALERT_EMAIL" az monitor action-group create -g "$RG" -n campux-oncall \ --short-name cxoncall \ --action email me "$ALERT_EMAIL" AG_ID=$(az monitor action-group show -g "$RG" -n campux-oncall --query id -o tsv) # fire if any Activity-log operation failed in the last 5 minutes az monitor scheduled-query create -g "$RG" -n campux-failed-ops \ --scopes "$WS_ID" \ --condition "count 'failedOps' > 0" \ --condition-query failedOps='AzureActivity | where ActivityStatusValue == "Failed"' \ --evaluation-frequency 5m --window-size 5m \ --severity 2 --action-groups "$AG_ID" \ --description "A management operation failed"
az monitor scheduled-query show -g "$RG" -n campux-failed-ops \
--query "{name:name, enabled:enabled, freq:evaluationFrequency}" -o table
The rule is configured, but this check does not prove that a failed operation occurred or that an email arrived. In production, verify the rule's evaluation and test the action group before trusting the notification path.Tear it down
Delete the resource group, and remove the subscription-level diagnostic setting separately — it lives on the subscription, not in the group.
az monitor diagnostic-settings subscription delete \
--name campux-activity-to-logs --subscription "$SUB_ID" --yes
az group delete -n campux-lab-obs-rg --yes
az group exists -n campux-lab-obs-rg # -> false
What you can now honestly claim
You created a Log Analytics workspace, routed real telemetry into it, queried that telemetry in KQL, and built a scheduled-query alert wired to an action group. That is "observability with Azure Monitor, Log Analytics, and thoughtful alerting" — a line lifted almost word-for-word from the job descriptions — done rather than described. KQL in particular is a transferable superpower: the same language queries Application Insights, Microsoft Sentinel, and Azure Resource Graph, so the query muscle you just built pays off far beyond this one workspace.
- The subscription Activity Log is collected automatically and retained for 90 days. Sending it to a workspace can avoid a direct ingestion charge for that data, but scheduled log alerts and notification features may be billed. Check current pricing for your configuration.
- There is a short delay — usually a few minutes — between an operation happening and it being queryable, because logs are batched on their way in. If a query returns nothing, that latency is the first thing to suspect, not a broken pipeline.