Metrics and logs — numbers and sentences
Everything you have built now runs without you: the pipeline deploys at merge, the job fires at 02:00, the app scales itself to zero and back. Automation's price is ignorance — nobody is watching, so nobody knows. Azure Monitor is the umbrella name for Azure's answer, and its telemetry comes in two shapes worth keeping strictly separate in your head. Metrics are numbers: CPU at 61 percent, 340 requests per minute, queue depth 12 — cheap to collect, sampled constantly, perfect for charts and thresholds. Logs are sentences: "02:04:11 — job pos-batch-job execution failed: connection to store 23 timed out" — rich, structured records of what happened, queryable like a database.1
- Metric vs log
- A metric is a number sampled over time — it tells you that something is happening and how much. A log is a recorded event with details — it tells you what happened and why. Dashboards and alerts run on metrics; investigations run on logs.
The two shapes answer different questions, and mixing them up wastes both. "Is the storefront slow right now?" is a metric question — one glance at a chart. "Why did store 23's upload fail last Tuesday?" is a log question — no chart will ever contain the answer, but a query over the job's log records will. Metrics are the smoke detector; logs are the security-camera footage. You need both, they are collected differently, and — the fact the whole next section turns on — only one of them shows up without being asked.
Diagnostic settings — nothing flows until you say so
Here is the surprise that finds every Azure engineer eventually, usually mid-incident. Platform metrics flow automatically — create a storage account and its charts are simply there. Resource logs do not. Every Azure resource is willing to narrate its life in detail — every blob read, every firewall denial, every job execution — but that narration is thrown away by default. It reaches a workspace only if you create a diagnostic setting on the resource: a small routing rule that says these log categories go there. No setting, no history. And the cruelty of the default is its timing: you discover the logs are missing at the exact moment you need them, and no setting created today can recover last night.2
The setting itself is small — a name, the log categories to route, and the destination workspace:
# open the valve on the storage account
az monitor diagnostic-settings create \
--name send-to-campux-logs \
--resource $(az storage account show -g rg-campux-platform \
-n campuxstorage --query id -o tsv) \
--workspace $(az monitor log-analytics workspace show \
-g rg-campux-platform -n campux-logs --query id -o tsv) \
--logs '[{"categoryGroup":"audit","enabled":true}]'
Because the valve must be opened per resource, the real engineering question is how to guarantee it is never forgotten — and you already own the answer. Class Eight's Azure Policy can require diagnostic settings on every resource of a given type, and its DeployIfNotExists effect can create them automatically the moment a resource is born. The valve stops being a checklist item humans forget and becomes a law of the subscription. That policy assignment is this class's case file, and it is the difference between "we log what we remembered to log" and "we log, full stop."
Workspace design — one or many
Where do all those routed logs land? A Log Analytics workspace: the reservoir at the end of the plumbing, storing records in typed tables you will query with KQL next class. The design question every organisation faces is deceptively simple — one workspace, or many? — and the modern default is emphatic:
- Start with one
- A single central workspace means every investigation happens in one place — the storage account's denials and the job's failures in the same query, joined. Correlation is the entire point of centralised logging, and every extra workspace is a wall through the middle of it.
- Split only for a named reason
- Data residency (logs that legally must stay in a region), hard billing separation between business units, or a genuinely separate security boundary. These are real reasons; "each team wanted its own" is not — access control has a better answer.
- Scope access, not storage
- The fear behind workspace sprawl is "team A should not read team B's logs" — solved by resource-context access: users with RBAC on a resource can query that resource's logs in the central workspace without seeing anyone else's. Class Eight, again, doing the work people try to do with architecture.
The anti-pattern has a recognisable shape: eleven workspaces, one per team, created over three years — and then an incident that spans two of them, and an engineer at 3am writing the same query twice and correlating timestamps by hand in a text editor. Fragmented logging converts every cross-cutting investigation into an archaeology project. One reservoir, well-governed, beats eleven puddles.
Retention and its invoice
The workspace bills like a reservoir: you pay for what flows in, and you pay for how long you keep it. Ingestion — billed per gigabyte — is usually the dominant cost, and it is set by the §2 valves: every log category you route is a running tap, and verbose categories (every blob read on a busy storage account, say) can pour surprising volumes. Retention is the second dial: how long records stay queryable. Interactive retention — the period you can query normally — comes with a default measured in weeks, extendable for a fee; beyond it, long-term retention keeps data for up to twelve years at low cost, retrievable when an auditor or a lawyer asks, but not sitting in your everyday queries.3
You cannot query the logs you never kept.
The discipline is to make both dials deliberate, per table, because the failure modes sit on both sides. Keep everything hot forever and monitoring quietly becomes a top-five line item — the Class Thirty-Two FinOps review will find it. Keep too little and you meet §2's cruelty in a new costume: the breach investigation that needs ninety days of sign-in history in a workspace that kept thirty. Security-relevant tables (sign-ins, audit, firewall) earn long retention; chatty debug categories earn short retention or a closed valve. The question to ask of every table is the same one Class Twelve asked of every storage tier: who needs this data, how old, and how fast? Price the answer, and write it down.
The posture interviews probe
"Tell me about your monitoring" is a standard interview prompt, and the weak answer lists products — "we had Azure Monitor and some dashboards." The strong answer describes a posture, and it has three legs. Coverage: telemetry flows from everything, by policy rather than memory — the §2 valve opened by law, so there is no resource whose failure would be invisible. A place: one workspace where signals meet, so a question that spans three services is one query, not three tabs. A habit: somebody actually looks — dashboards reviewed, alerts triaged (Class Thirty's subject), and the monitoring itself checked for gaps before incidents find them.
Notice what the posture is for. Monitoring does not prevent failures — the job will still break some night, disks will still fill, certificates will still expire. What it changes is the shape of the morning after: the difference between "the job failed at 02:04, at the connection to store 23, here is the record" and "the job apparently hasn't run for nine days and nobody can say why." Class One's outage took nine hours partly because diagnosis started from nothing. The posture you build this class is what makes sure no Campux investigation ever starts from nothing again — and being able to say that sentence, with the policy assignment to back it, is worth more in an interview than naming every product in the Azure Monitor family.
Eyes on the estate, by law
Campux stands up one workspace — campux-logs in rg-campux-platform, written in Bicep like everything else — and resists the committee's suggestion of one-per-team with §3's argument: the storefront, the batch job, and the storage account must be joinable, because incidents do not respect team boundaries. Then the Class Eight muscle memory: a policy assignment with DeployIfNotExists that creates diagnostic settings automatically on every storage account, key vault, and Container Apps environment in the subscription, routing to the central workspace. Nobody opens valves by hand anymore; being born in the subscription means being plumbed in.
The first payoff arrives inside a month, and it is not an outage — it is the absence of a mystery. The POS job fails one night (store 23's upload was corrupt), and the on-call engineer reads the execution's failure record over coffee: what failed, when, which store, first try. Total investigation time: four minutes. The Class One version of Campux spent nine hours on its outage largely because minute one started with nothing. This Campux starts every investigation with the tape already rolling — and next class teaches the language that interrogates it.
The official pages, and a CAMPUX overview
Azure Monitor overview
learn.microsoft.com/azure/azure-monitor/fundamentals/overview
Log Analytics workspace overview
learn.microsoft.com/azure/azure-monitor/logs/log-analytics-workspace-overview
The Figure 15 plumbing traced live — a resource with the valve closed and its empty workspace, the diagnostic setting created, and the first rows arriving minutes later — will live here. Video to be added.
Build the plumbing, and feel the closed valve first
Create the reservoir, generate activity with the valve closed, see the workspace stay empty, then open the valve and watch rows arrive. This is §2 as an experience — the order of steps is the lesson.
Create a workspace and a storage account to spy on:
az group create --name rg-monitor-lab --location eastus az monitor log-analytics workspace create \ --resource-group rg-monitor-lab --workspace-name campux-logs-lab az storage account create --name campuxmon$RANDOM \ --resource-group rg-monitor-lab --sku Standard_LRS # note the storage account name it prints — you need it belowWhat to notice: the workspace is a plain resource — no agents, no magic. It is an empty reservoir until something is routed into it.Generate activity before any diagnostic setting exists — make a container, upload a blob, list it:
az storage container create --name receipts \ --account-name <yourstorage> --auth-mode login echo "store-23 upload" > r1.txt az storage blob upload --container-name receipts --file r1.txt \ --name r1.txt --account-name <yourstorage> --auth-mode login
What to notice: real operations are happening — reads, writes, authentications. The resource is narrating all of it. Nothing is listening.Now open the valve — create the diagnostic setting routing storage audit logs to the workspace:
STG_ID=$(az storage account show -g rg-monitor-lab \ -n <yourstorage> --query id -o tsv) WS_ID=$(az monitor log-analytics workspace show -g rg-monitor-lab \ -n campux-logs-lab --query id -o tsv) az monitor diagnostic-settings create --name lab-valve \ --resource "$STG_ID/blobServices/default" --workspace "$WS_ID" \ --logs '[{"categoryGroup":"audit","enabled":true}]'What to notice: the setting is attached to the blob service of the account, names its categories, and points at the workspace — Figure 15's valve, in one command. Upload two or three more blobs now to generate post-valve traffic.Wait five to ten minutes (ingestion is not instant), then query the workspace — first for the pre-valve era, then at all:
az monitor log-analytics query --workspace $(az monitor \ log-analytics workspace show -g rg-monitor-lab \ -n campux-logs-lab --query customerId -o tsv) \ --analytics-query "StorageBlobLogs | project TimeGenerated, OperationName, StatusText | order by TimeGenerated desc" \ -o table
The lesson: rows exist — operation names, timestamps, status — but only from after step 3. The blobs you uploaded in step 2 left no trace, and no setting created now will ever recover them. That gap is the empty-workspace surprise, deliberately felt in a lab instead of an incident. Keep everything running: Lab 2 uses this workspace.
Turn the two cost dials with your own hands
Read the workspace's retention, change it, and find where ingestion volume — the thing you will actually be billed for — is measured.
Read the current retention setting:
az monitor log-analytics workspace show \ --resource-group rg-monitor-lab \ --workspace-name campux-logs-lab \ --query retentionInDays
What to notice: the default is measured in weeks, not years. If this workspace held sign-in logs and a breach investigation needed day 60, the default would already have deleted it.Turn the dial — extend interactive retention:
az monitor log-analytics workspace update \ --resource-group rg-monitor-lab \ --workspace-name campux-logs-lab \ --retention-time 90
What to notice: one property, real billing consequences — longer interactive retention costs more per GB kept. In production this is set per table, not per workspace: sign-in logs long, debug chatter short. §4's discipline is exactly this command, made deliberate.Find the meter — query the workspace's own record of what it ingested:
az monitor log-analytics query --workspace $(az monitor \ log-analytics workspace show -g rg-monitor-lab \ -n campux-logs-lab --query customerId -o tsv) \ --analytics-query "Usage | summarize TotalGB=sum(Quantity)/1000 by DataType | order by TotalGB desc" \ -o table
On screen: a table of data types and gigabytes — the workspace metering itself, queryable like everything else. In a real estate this query names your most expensive tap, and closing or filtering one noisy category is routinely the biggest monitoring cost win available.Clean up the lab:
az group delete --name rg-monitor-lab --yes --no-wait
The lesson: two dials — what flows in (the §2 valves, measured by the Usage table) and how long it stays (retention, per table in production). Every monitoring bill that ever shocked a manager was one of these two dials left on default. You now know where both of them are.
Asking the data, not the room
Users report a vague slowness and nobody can point at anything. You are not blind — telemetry is already flowing to Log Analytics because you turned on diagnostics up front. You open the workspace and start asking the data questions instead of asking the room. The difference between a guess and an answer is whether the logs were being collected before you needed them.
Examination
Four drills, then two situations. The situations have no marking scheme — write your answer before you reveal the reasoning, or the exercise is worthless. Nothing is stored; this is between you and the page.
B. The question names a specific event with a cause — that is a sentence, and sentences live in logs. A metric could tell you that something was wrong at 02:04 (executions dropped, errors ticked up), but no number contains "store 23" or "connection timed out"; charts detect, records explain. C is the tempting flattener and it is false — metrics are pre-aggregated numbers and logs are structured events, collected and billed differently, which is why §2's valve applies to one and not the other. D describes the world before centralised logging: attaching a debugger to a 02:00 batch job is what teams without a workspace end up attempting. Detection is metrics; diagnosis is logs. Keep the verbs straight and every tooling choice follows.
C — and this answer decides audits and breach investigations. Resource logs are a stream, not an archive: with no diagnostic setting, the vault's narration was discarded as it happened, and there is no six-month buffer waiting to be released (A) nor a 30-day one (B). The setting is a valve on a live pipe — it routes what flows from the moment it opens, minutes later at most (D overstates even that delay). The professional consequences are direct: if that vault held production secrets, you now cannot answer "who read them in May?", and no amount of money fixes it retroactively. This is why the case file opens valves by policy at resource creation — the only diagnostic setting that protects you is the one that existed before the question did.
Metrics automatic, logs by valve, valves by policy. The two rejects are the class's two expensive misunderstandings. A workspace collecting nothing is not a paradox — it is Tuesday: the reservoir and the plumbing are separate objects, and Lab 1's step-2 blobs proved that activity plus workspace still equals empty without the setting between them. And the billing model is the reverse of the last reject: ingestion is precisely what you pay for (per GB, per §4), while interactive queries over retained data are not the meter. Teams that believe "queries cost, so query less" optimise the free thing; teams that believe "ingestion is free" open every valve to full and meet the invoice. The Usage table from Lab 2 settles both arguments with numbers.
# postmortem: storefront checkout errors, 03:10–04:40
1. Detection: metric alert on 5xx rate fired at 03:12 —
on-call was paged within two minutes.
2. Diagnosis: the app's error logs could not be found in the
workspace; the app was deployed last quarter and no
diagnostic setting was ever created for it.
3. Recovery: rolled back to the previous revision at 04:35;
errors stopped.
4. Follow-up: on-call will remember to enable diagnostics
on new resources going forward.
Line four. Line two describes the wound accurately — a closed valve discovered mid-incident, ninety diagnostic-free minutes of guessing — but line four is where the postmortem fails, because it prescribes memory as the cure for forgetting. "On-call will remember" is the same mechanism that already failed last quarter, restated as an intention. The Class Twenty-Five instinct applies: a fix that depends on a human remembering is not a fix; it is a scheduled recurrence.
The repair is one policy assignment: DeployIfNotExists creating diagnostic settings on every new resource of the relevant types, plus a one-time remediation sweep over everything already deployed — after which line two becomes structurally impossible, not just discouraged. The other lines are healthy: metric alerts detecting 5xx spikes is exactly the metrics-detect half of §1 working (A), rollback is a respectable recovery (B), and D is Drill 02's misconception wearing a new hat — workspaces collect nothing by default. Postmortems are judged by whether their follow-ups are mechanisms or promises. Mechanisms compound; promises reset at the next staff change.
Concede the fair core before defending anything. The director's premise — we pay, therefore we should see — is reasonable, and the honest opening is that paying for Azure Monitor buys the capability to see, not the seeing. Then give the diagnosis in the class's terms, without jargon: telemetry in Azure flows only where valves were opened, and the audit that follows this outage will almost certainly find some closed — resources without diagnostic settings, logs kept shorter than the incident's fuse was long, or signals that landed in a workspace no alert and no human ever read. "We had monitoring" usually decomposes into "we had charts nobody was assigned to."
Answer the actual question — "why didn't we see it coming" — with the two honest halves. Half one: some failures genuinely do not announce themselves in advance, and monitoring's real promise for those is a fast, evidence-rich after — minutes to diagnosis instead of the ninety guessing minutes just endured. Half two: many failures do announce themselves — climbing error rates, filling disks, expiring certificates — but only if something is watching the right signal with a threshold and a pager attached, which is alerting, which is configuration, which is work that either was or was not done. The tool detected nothing because nothing was aimed. That sentence stings, and it is the true one.
Convert frustration into the posture, with a bill attached. Offer the §5 three legs as the concrete follow-up: coverage by policy (valves opened automatically, so no resource is ever dark again), one workspace (so the next investigation is one query), and a habit (named owners for alerts and a monthly gaps review — Class Thirty makes this real). Price it honestly: some ingestion cost, a few days of engineering, and a standing hour a week. The director is not really asking about last night; they are asking whether next time will be different. The answer is yes — not because the product changed, but because the posture will exist. Bring the policy assignment to the follow-up meeting, not a slide.
Take the three reasons seriously — then test each against what workspaces actually separate. "Our access": solved inside one workspace by resource-context RBAC — a team with rights to its resources queries those resources' logs and nobody else's; Class Eight's tooling, not architecture, is the answer to a permissions question. "Our budget": ingestion is attributable — the Usage table and cost views can split the bill by resource and table, so chargeback does not require separate plumbing. "Our logs": this is the one that is usually a feeling rather than a requirement — and the feeling is legitimate, but it prices out badly, as the next paragraph should say out loud.
Name the cost of splitting, with the 3am scene. Incidents do not respect team boundaries: the storefront error that traces to a storage throttle that traces to a batch job touches three teams' resources in one causal chain. In one workspace that is a single query; across three it is an engineer at 3am running the same KQL three times and lining up timestamps by hand. Fragmentation taxes exactly the moments the logs exist for. The §3 rule gives the decision structure: split for data residency, regulatory boundaries, or genuinely separate security domains — and concede honestly that if one of the three teams does have such a requirement (a compliance scope, a sovereignty constraint), that team gets its workspace, because the rule is "named reason", not "never".
Close with the offer that dissolves the politics. Most workspace-sprawl requests are really requests for autonomy dressed as infrastructure — so give the autonomy without the fragmentation: each team gets scoped query access, its own dashboards and alerts over its own resources, and a monthly cost line it can see and control. One reservoir, three sovereign views. If a lead still objects, the closing question usually settles it: "in the next cross-team incident, which of your engineers volunteers to be the one correlating three workspaces by hand?" Silence, in this meeting, is agreement.
Five things worth carrying out of this class
- Metrics are numbers (cheap, automatic, detect); logs are sentences (rich, routed, diagnose). Dashboards and alerts run on the first; investigations run on the second.
- Nothing flows until you say so: resource logs reach a workspace only through a diagnostic setting, and no setting created today recovers yesterday. The valve ships closed.
- Open valves by law, not memory — Azure Policy with DeployIfNotExists creates diagnostic settings at resource birth, which is the difference between "we log what we remembered" and "we log".
- One workspace is the default; split only for a named reason (residency, regulation, security boundary). Scope access with RBAC, attribute cost with the Usage table — correlation is the point of centralising.
- The bill has two dials: what flows in (per-GB ingestion, set by the valves) and how long it stays (interactive vs long-term retention, per table). Both left on default is how monitoring becomes a surprise line item — or a missing witness.
- Azure Monitor's family is larger than this class's two shapes — traces, changes, Prometheus metrics in their own workspace type, and more. The metrics/logs split remains the honest backbone: nearly every tool in the family is a producer, store, or consumer of one of the two, and knowing which one you are looking at tells you how it is collected, billed, and queried. Meet the cousins as you need them. ↩
- The Activity Log — the subscription's own record of who created, changed, or deleted what — is the one log you get without a valve: ninety days of it, automatically. It answers "who touched this resource?" but nothing about what happens inside resources, which is exactly the gap diagnostic settings exist to fill. Route it to the workspace too; ninety days is shorter than most audits. ↩
- Retention specifics move: defaults differ by table type, interactive retention extends to two years for a fee, long-term retention reaches twelve, and the table-level knobs have grown finer-grained over time. Treat the architecture as settled — a hot, queryable window backed by a cheap, deep archive — and check current limits and prices when you set real dials. The direction that never changes: decide per table, on purpose, before the auditor asks. ↩