AZ-104 Refresher Chapter 9 Β· Monitoring

Chapter 9

Monitoring: metrics, logs, alerts and Network Watcher

πŸ“– Theory 35 minπŸ›  Lab 20 minMonitor & maintain Β· 10–15%

You've built a small but real environment. Now you need to see what it does and hear when something goes wrong. This chapter covers Azure Monitor (metrics, logs, KQL, alerts, Insights) and Network Watcher. Everything in the lab points at resources you already have.

Part A

Theory

Azure Monitor in one picture

Azure Monitor is the umbrella for collecting, analysing and acting on telemetry. It works with two main kinds of data, and almost every question in this area comes down to "is this a metric or a log, and how does it get there?"

Sources Applications Guest OSneeds AMA + DCR Azure resourcesplatform metrics + logs SubscriptionActivity log TenantEntra sign-in/audit Data stores Metricsnumbers over timenear real-time Β· 93 daysautomatic for resources Logsrecords in a Log Analyticsworkspace Β· KQLneeds diagnostic settingsor an agent Use it Metrics explorer Log queries Insights Workbooks Alert rules Actiongroupmail Β· runbook… Alert processing rules can suppress or add action groups between the alert and the action group.
Metrics arrive automatically; most logs must be sent somewhere with a diagnostic setting or an agent.

Metrics

Platform metrics (like a VM's Percentage CPU or a storage account's Transactions) are collected automatically, every minute, and kept for 93 days. You don't configure anything. Note that a VM's platform metrics come from the host; metrics from inside the OS (memory used, disk free space) need the Azure Monitor Agent.

In Metrics explorer you build a chart by picking a scope, a metric and an aggregation. Reading those charts correctly is a skill the exam tests:

Logs and Log Analytics

Types of logs

Diagnostic settings

A diagnostic setting on a resource (or subscription) sends selected log categories and/or metrics to one or more destinations:

A resource can have up to five diagnostic settings. For storage accounts, diagnostic settings are per service (blob, file, queue, table). At scale, you deploy diagnostic settings with Azure Policy (DeployIfNotExists, chapter 2).

Log Analytics workspaces

A Log Analytics workspace stores log data in tables (AzureActivity, Heartbeat, Perf, StorageBlobLogs…). Things to know:

Querying with KQL

Kusto Query Language (KQL) reads like a pipeline: start with a table, then pass the rows through operators with |. You don't need to be an expert, but you must be able to read a query and say what it returns.

// How many operations did each person do in the last day?
AzureActivity
| where TimeGenerated > ago(1d)
| where ActivityStatusValue == "Success"
| summarize Operations = count() by Caller
| order by Operations desc
| take 10
OperatorDoesSQL equivalent
whereFilter rowsWHERE
projectChoose (and rename) columnsSELECT
extendAdd a calculated columnSELECT …, x AS y
summarize … byAggregate: count(), avg(), max(), dcount()…GROUP BY
bin(TimeGenerated, 5m)Group times into buckets
order by / sort by, take / topSort, limitORDER BY, TOP
join, unionCombine tablesJOIN, UNION
render timechartDraw a chart

String comparisons: == is case-sensitive, =~ isn't; contains matches substrings, has matches whole terms (and is faster).

Alerts

An alert rule has four parts:

  1. Scope: the resource(s) to watch. A metric alert can cover many VMs of one type in one region at once.
  2. Condition: the signal and its logic. Signal types:
    • Metric: "avg CPU > 80% over 5 minutes". Static threshold or dynamic thresholds (machine learning learns what's normal).
    • Log search: a KQL query, run on a schedule, that fires when results meet a condition.
    • Activity log: "someone deleted a VM", "a policy denied a request", Service Health (Azure incidents and planned maintenance in your regions) and Resource Health (your specific resource became unavailable).
  3. Actions: one or more action groups.
  4. Details: name and severity from Sev 0 (critical) to Sev 4 (verbose).

Metric alerts are stateful by default: they fire once, and resolve automatically when the condition is no longer true. An alert instance has a monitor condition (Fired / Resolved) and a user response you set (New, Acknowledged, Closed).

Action groups

An action group is a reusable list of who to notify and what to run:

There are rate limits: for example no more than one SMS every 5 minutes and about 100 emails per hour per address. So an alert storm doesn't flood your phone.

Alert processing rules

Alert processing rules act on alerts after they fire, without editing each alert rule. Two uses:

A rule has a scope (subscription, resource group, resources), optional filters (severity, alert rule name, resource type, monitor service…) and an optional schedule (once, daily, weekly).

Exam trap

"Stop notifications for all alerts in a resource group during a monthly maintenance window, with the least effort." Not "disable every alert rule": create one alert processing rule with suppression and a schedule.

Insights

Insights are ready-made monitoring experiences for specific resource types, built on metrics, logs and workbooks:

Network Watcher

Network Watcher is a regional service for diagnosing IaaS network problems. It's enabled automatically per region (in a resource group called NetworkWatcherRG). Know which tool answers which question:

QuestionTool
"Is this packet allowed or denied by an NSG, and by which rule?"IP flow verify
"Which NSG rules apply, and in what order?"NSG diagnostics / Effective security rules
"Where does traffic to this IP go? Is a UDR sending it somewhere odd?"Next hop / Effective routes
"Can VM A reach host B on port X right now, and if not, why?"Connection troubleshoot
"Alert me when latency or reachability between A and B changes, over time."Connection Monitor
"What's actually on the wire?"Packet capture
"Why is my VPN tunnel down?"VPN troubleshoot
"Who talks to whom, how much traffic, allowed or denied?"Flow logs + Traffic analytics
"What does my network look like?"Topology

Flow logs record IP traffic. VNet flow logs are the current version; the older NSG flow logs can no longer be created new and are being retired. Flow logs are written to a storage account, and Traffic analytics processes them into a Log Analytics workspace for dashboards.

Connection Monitor runs continuous tests from sources (Azure VMs, scale sets, on-premises machines with the agent) to destinations (VMs, URLs, IPs, FQDNs) over TCP, HTTP or ICMP. It reports checks failed % and round-trip time, and you can alert on them.

AZ-305 link

AZ-305 asks you to design a monitoring solution: how many workspaces (and where, for data residency), which logs go where (workspace for analysis, storage for cheap archive, Event Hubs for a SIEM), and how to enforce it with Azure Policy. Remember: activity log 90 days by default; longer means a diagnostic setting.

Self-check

1. Auditors need to know who deleted a VM 5 months ago. Nothing was configured. Can you find out?

C. Set up a subscription diagnostic setting now for the future.

2. You want to query a Key Vault's access events with KQL. What must you configure?

A. Resource logs need a diagnostic setting; agents are for VMs.

3. A VM can't reach 10.50.0.4. You suspect a UDR sends traffic to a firewall that's down. Which tool shows that quickest?

D. Next hop returns the next hop type, IP and the route table used.

4. What does this query return? Heartbeat | summarize max(TimeGenerated) by Computer

B. A common query to find agents that stopped reporting.

5. You need memory usage (% used) of Linux VMs in Azure Monitor. What do you need?

C. The host can't see inside the guest's memory use. (There's an "Available Memory Bytes" platform metric, but not % used per process.)

Part B

Lab: watch your environment

Everything here uses log-az104 (chapter 4), the VMs (chapter 5), the load balancer (chapter 6), the storage account (chapter 7) and the route from chapter 3. Start the VMs and paste the variables:

RG=rg-az104-lab; LOC=westeurope; LOC2=northeurope; INIT=xx
ST=staz104${INIT}01
az vm start -g $RG -n vm-web1 --no-wait; az vm start -g $RG -n vm-web2 --no-wait
LAWID=$(az monitor log-analytics workspace show -g $RG -n log-az104 --query id -o tsv)
  1. Task

    Read the metrics

    Build one chart with the CPU of both web VMs as separate lines over the last 4 hours, and decide whether Avg or Max aggregation is more useful to spot short spikes. Build a second chart for lbe-web showing Data Path Availability. Pin both to a dashboard.

    Done when
    • A dashboard shows both charts.
    Solution Β· Portal
    1. Monitor β†’ Metrics β†’ scope: select both VMs (same type and region) β†’ metric Percentage CPU, aggregation Max β†’ Apply splitting by Resource (if offered) or add a second metric line.
    2. Time range Last 4 hours. Save to dashboard β†’ Pin to dashboard (new dashboard az104).
    3. New chart: scope lbe-web, metric Data Path Availability, aggregation Avg β†’ pin.

    Max shows short spikes; Avg over 5 minutes smooths them away.

  2. Task

    Collect the logs that aren't collected by default

    Send to log-az104:

    • the subscription's activity log (all categories);
    • the blob service logs of your storage account (read, write, delete) plus its transaction metrics.

    Then read a blob (e.g. download hello.txt in the portal's storage browser) so there's something to see.

    Done when
    • Both diagnostic settings exist.
    • After 5–15 minutes, the tables AzureActivity and StorageBlobLogs have rows.
    Solution Β· Portal
    1. Monitor β†’ Activity log β†’ Export Activity Logs β†’ Add diagnostic setting: tick all categories, destination Send to Log Analytics workspace β†’ log-az104.
    2. Storage account β†’ Monitoring β†’ Diagnostic settings β†’ blob β†’ Add diagnostic setting: StorageRead, StorageWrite, StorageDelete, metric Transaction β†’ log-az104.
    Solution Β· Azure CLI
    az monitor diagnostic-settings subscription create -n diag-activity --location $LOC --workspace $LAWID --logs '[
     {"category":"Administrative","enabled":true},{"category":"Security","enabled":true},
     {"category":"ServiceHealth","enabled":true},{"category":"Alert","enabled":true},
     {"category":"Recommendation","enabled":true},{"category":"Policy","enabled":true},
     {"category":"Autoscale","enabled":true},{"category":"ResourceHealth","enabled":true}]'
    
    STID=$(az storage account show -g $RG -n $ST --query id -o tsv)
    az monitor diagnostic-settings create -n diag-blob --resource $STID/blobServices/default --workspace $LAWID \
      --logs '[{"category":"StorageRead","enabled":true},{"category":"StorageWrite","enabled":true},{"category":"StorageDelete","enabled":true}]' \
      --metrics '[{"category":"Transaction","enabled":true}]'
  3. Task

    Look inside the VMs

    Enable VM insights for both web VMs, sending data to log-az104. Find out which extension got installed and which data collection rule was created.

    Done when
    • Monitor β†’ Virtual Machines β†’ Performance shows CPU and memory for both VMs (allow 10–15 minutes).
    • You can name the agent extension and the DCR.
    Solution Β· Portal
    1. vm-web1 β†’ Monitoring β†’ Insights β†’ Enable β†’ choose Azure Monitor Agent, create or pick a data collection rule (e.g. MSVMI-az104) targeting log-az104; process/dependency map optional β†’ Configure.
    2. Repeat for vm-web2 with the same DCR.
    3. The VM's Extensions + applications shows AzureMonitorLinuxAgent; the DCR is under Monitor β†’ Data Collection Rules.
  4. Task

    Get an email when a web server is overloaded

    Create an action group ag-az104-email that emails you. Then create one metric alert rule alert-vm-cpu that covers both web VMs and fires at Sev 2 when average CPU is above 80% over 5 minutes. Trigger it by loading the CPU of vm-web1.

    Done when
    • You receive the "Fired" email, and later a "Resolved" email.
    • Monitor β†’ Alerts shows the alert; you change its state to Acknowledged.
    Hint

    For load: Run command timeout 900 sh -c 'yes > /dev/null' keeps one core at 100% for 15 minutes.

    Solution Β· Portal
    1. Monitor β†’ Alerts β†’ Action groups β†’ Create: name ag-az104-email, display name az104, Notifications: Email/SMS/Push/Voice β†’ your email.
    2. Monitor β†’ Alerts β†’ Create β†’ Alert rule: scope β†’ filter resource type Virtual machines, select both VMs. Condition Percentage CPU, static, Average, greater than 80, check every 1 min, lookback 5 min. Actions: ag-az104-email. Details: Sev 2, name alert-vm-cpu.
    3. vm-web1 β†’ Run command β†’ timeout 900 sh -c 'yes > /dev/null'.
    Solution Β· Azure CLI
    az monitor action-group create -g $RG -n ag-az104-email --short-name az104 --action email me <your-email>
    VM1=$(az vm show -g $RG -n vm-web1 --query id -o tsv); VM2=$(az vm show -g $RG -n vm-web2 --query id -o tsv)
    az monitor metrics alert create -g $RG -n alert-vm-cpu --scopes $VM1 $VM2 \
      --target-resource-type Microsoft.Compute/virtualMachines --region $LOC \
      --condition "avg Percentage CPU > 80" --window-size 5m --evaluation-frequency 1m \
      --severity 2 --action ag-az104-email
    az vm run-command invoke -g $RG -n vm-web1 --command-id RunShellScript \
      --scripts "nohup timeout 900 sh -c 'yes > /dev/null' >/dev/null 2>&1 &"
  5. Task

    Silence alerts during maintenance

    Next Saturday from 22:00 to 23:00 you'll patch the VMs. Make sure no alert in rg-az104-lab sends notifications in that window, without changing or disabling any alert rule.

    Done when
    • An alert processing rule with a one-time schedule and suppression exists for the resource group.
    Solution Β· Portal

    Monitor β†’ Alerts β†’ Alert processing rules β†’ Create: scope rg-az104-lab, rule type Suppress notifications, scheduling At a specific time, start Saturday 22:00, end 23:00 (your time zone), name apr-maintenance.

    Solution Β· Azure CLI
    RGID=$(az group show -n $RG --query id -o tsv)
    # change the dates to your next Saturday
    az monitor alert-processing-rule create -g $RG -n apr-maintenance --rule-type RemoveAllActionGroups \
      --scopes $RGID --schedule-start-datetime "2026-11-21 22:00:00" --schedule-end-datetime "2026-11-21 23:00:00" \
      --schedule-time-zone "W. Europe Standard Time" --description "Patch window"
  6. Task

    Answer questions with KQL

    In log-az104 β†’ Logs, write queries that answer:

    1. When did each VM last send a heartbeat?
    2. What was the CPU utilisation per VM in 5-minute buckets over the last hour, as a chart? (You should see your load test.)
    3. Who did which operations in your subscription today?
    4. Which blob operations hit your storage account, with status and caller IP?
    Done when
    • All four queries return results, and query 2 shows a time chart with the CPU spike.
    Hint

    Tables: Heartbeat, InsightsMetrics (VM insights; namespace Processor, name UtilizationPercentage), AzureActivity, StorageBlobLogs.

    Solution Β· KQL
    // 1
    Heartbeat
    | summarize LastSeen = max(TimeGenerated) by Computer
    
    // 2
    InsightsMetrics
    | where TimeGenerated > ago(1h)
    | where Namespace == "Processor" and Name == "UtilizationPercentage"
    | summarize CPU = avg(Val) by bin(TimeGenerated, 5m), Computer
    | render timechart
    
    // 3
    AzureActivity
    | where TimeGenerated > ago(1d)
    | summarize Operations = count() by Caller, OperationNameValue
    | order by Operations desc
    
    // 4
    StorageBlobLogs
    | where TimeGenerated > ago(1d)
    | project TimeGenerated, OperationName, StatusCode, CallerIpAddress, Uri
    | order by TimeGenerated desc
  7. Task

    Diagnose the network with Network Watcher

    • Prove that traffic from vm-web1 to 203.0.113.10 is dropped, and name the route that drops it.
    • Check right now whether vm-web1 can reach your storage account's file endpoint on port 445, and which IP it connects to.
    • Set up continuous monitoring (every 30 seconds) from vm-web1 to the file endpoint on 445 and to www.microsoft.com on 443, named cm-az104.
    Done when
    • Next hop: type None, route blackhole-testnet (from chapter 3).
    • Connection troubleshoot: Reachable, via 10.20.2.x (the private endpoint).
    • cm-az104 shows checks and round-trip times for both destinations.
    Solution Β· Portal
    1. Network Watcher β†’ Next hop: VM vm-web1, source IP its private IP, destination 203.0.113.10.
    2. Network Watcher β†’ Connection troubleshoot: source vm-web1, destination Manually staz104xx01.file.core.windows.net, TCP port 445. (It installs the Network Watcher agent if needed.)
    3. Network Watcher β†’ Connection monitor β†’ Create: name cm-az104, region; test group with source vm-web1, destinations: External addresses staz104xx01.file.core.windows.net and www.microsoft.com; test configurations TCP 445 and HTTPS 443, frequency 30 s; workspace log-az104.
    Solution Β· Azure CLI
    IP1=$(az vm show -g $RG -n vm-web1 -d --query privateIps -o tsv)
    az network watcher show-next-hop -g $RG --vm vm-web1 --source-ip $IP1 --dest-ip 203.0.113.10
    az network watcher test-connectivity -g $RG --source-resource vm-web1 \
      --dest-address $ST.file.core.windows.net --dest-port 445 \
      --query "{status:connectionStatus, hops:hops[].address}"
    # Connection Monitor is easiest in the portal (see the portal solution).
Cost

VM insights, the activity log and blob logs send a small amount of data (well under 1 GB for this lab, a few euros at most). Connection Monitor tests are cheap at this scale. You delete everything in chapter 10.

Checkpoint
  • Activity log and blob logs flow into log-az104; VM insights runs on both VMs.
  • Action group ag-az104-email, alert rule alert-vm-cpu, alert processing rule apr-maintenance.
  • Connection monitor cm-az104 watches the path from vm-web1 to storage.