CAMPUX Cloud Bootcamp Lab · Observability ← All labs
Hands-On Lab · Intermediate
~35 min · Free tier · Cloud Shell
CLI & KQL · torn down at the end
Observability · Monitoring

See what your cloud is doing, in KQL.

Anyone can deploy a resource; the job is knowing what it does next. Stand up a Log Analytics workspace, stream your subscription's own activity into it, ask questions of that data in KQL, and wire an alert that pages you when something fails — the monitoring loop every posting lists.

Fig. 1 · From Activity log to a KQL alert
Resource group · rg-lab-obsstreamquery → alertActivity lograw eventsLog Analyticsquery in KQLAlert rulefires on a matchlogs you cannot query are just storage
● Screen walkthrough Not yet recorded · ~7 min
Reel · 00:00 / 07:00

Shape a KQL query result-by-result, build an alert on it, then trigger the alert on purpose.

Placeholder — the page below stands alone until the reel lands
Why

Logs you cannot query are just storage

Every Azure resource emits telemetry, but scattered across a hundred blades it is noise. Observability is the discipline of pooling that telemetry in one place and being able to ask it questions — which is what a Log Analytics workspace and its query language, KQL, are for. This lab uses a data source you already generate for free: the subscription Activity log, the audit trail of every management operation you run. You will pipe it into a workspace, query it, and then turn a query into an alert — the exact shape of production monitoring, where a KQL expression that returns rows is what wakes someone up.

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.

Before you begin — one-time setup

You need a free Azure account, the Azure CLI (az), then be signed in with az login. First time? The 15-minute Set up your machine page covers the account, the installs (winget / brew / apt), and sign-in. Prefer zero installs? Run everything in Azure Cloud Shell (Bash), preinstalled and already signed in.

The companion repository

This page is the full lab; the workspace and alert as Bicep are in github.com/kloudcaptain/campux-labs under lab-observability-kql. Run everything in Azure Cloud Shell (Bash). Log Analytics includes a free daily ingestion allowance, and the Activity log is free to stream — this lab stays within it.

Setup

A workspace to collect into

Create a resource group and a Log Analytics workspace. The workspace is the pool everything queryable lands in.

# 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"
Checkpoint The workspace exists and you have captured two identifiers — the full resource id (used to wire data in) and the customerId GUID (used to query). Empty for now; the next step gives it something to collect.
Step 1

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.

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
Checkpoint The diagnostic setting is created and enabled. Activity-log records take a few minutes to surface in the workspace — a good moment to stretch. The ping you just did will show up as Microsoft.Resources/subscriptions/resourceGroups/write and …/delete operations.
Step 2

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
Checkpoint You get rows back — your own operations from the last hour, grouped and counted, including the resource-group write and delete from the ping. If it is empty, the data has not landed yet — Activity-log ingestion is genuinely slow to start on a new workspace, often 10–15 minutes for the first records (a few minutes on a warm one); wait and re-run. That round trip — a question in KQL, an answer from real telemetry — is the core skill this lab exists to give you.
Step 3

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.

# who to notify (put your own email in)
az monitor action-group create -g "$RG" -n campux-oncall \
  --short-name cxoncall \
  --action email me [email protected]

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 'placeholder' > 0" \
  --condition-query placeholder='AzureActivity | where ActivityStatusValue == "Failure"' \
  --evaluation-frequency 5m --window-size 5m \
  --severity 2 --action-groups "$AG_ID" \
  --description "A management operation failed"
Checkpoint Confirm the rule exists and is enabled:
az monitor scheduled-query show -g "$RG" -n campux-failed-ops \
  --query "{name:name, enabled:enabled, freq:evaluationFrequency}" -o table
You now have the full loop: data flowing in, a question expressed as KQL, and an action group that turns a non-empty result into an email. Point the same pattern at an app's exceptions or a VM's CPU and you have production monitoring.
Down

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
Checkpoint The group is gone and the diagnostic setting is removed, so nothing keeps streaming or billing. Your subscription is back where it started.
End

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.

Footnotes
  1. Activity-log data is ingested free, and Log Analytics grants a daily free allowance beyond that, so this lab stays at no cost. A busy production workspace does bill for ingestion and retention — which is exactly why cost-aware query and retention design is part of the observability job.
  2. 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.