Azure Monitor raccoglie telemetria in un Log Analytics workspace, dove i dati risiedono in tabelle interrogabili con KQL (Kusto Query Language). Per l’amministratore Azure, KQL non è opzionale: è lo strumento con cui si diagnosticano problemi, si costruiscono dashboard e — soprattutto — si definiscono i log alert. Capire come una query si trasforma in una regola di allerta è uno dei nodi centrali di AZ-104.

Il modello dei dati e le tabelle comuni

Ogni sorgente scrive in una tabella con schema noto. Le tre che ricorrono all’esame:

  • Heartbeat — un record periodico (ogni minuto) inviato dagli agenti (Azure Monitor Agent). Serve a verificare quali VM sono “vive”: l’assenza di heartbeat è il segnale classico di una macchina down.
  • AzureActivity — l’Activity Log a livello di control plane: chi ha creato, modificato o eliminato una risorsa, con Caller, OperationNameValue e ActivityStatusValue. È la tabella per audit e governance.
  • Perf — contatori di performance guest (CPU, memoria, disco) raccolti tramite Data Collection Rules (DCR). I dati vivono nelle colonne ObjectName, CounterName, CounterValue, InstanceName.

Gli operatori fondamentali

Una query KQL è una pipeline: la tabella iniziale scorre attraverso operatori separati da |, ciascuno che trasforma il set di righe.

  • where — filtra le righe. Va messo il prima possibile, specialmente sul tempo (TimeGenerated), per ridurre il volume scandito.
  • project — seleziona/rinomina le colonne da mantenere (project-away per escludere).
  • summarize — aggrega: applica funzioni come avg(), count(), max() raggruppando per by.
  • join — combina due tabelle su una chiave comune (es. correlare Heartbeat e Perf sullo stesso Computer).
  • render — istruisce il portale a disegnare il risultato come timechart, barchart, ecc. È puramente di presentazione.

Costruire trend e aggregazioni

Per un trend temporale la chiave è bin(), che arrotonda TimeGenerated a intervalli fissi creando “secchi” (bucket) per l’asse X:

Perf
| where TimeGenerated > ago(24h)
| where CounterName == "% Processor Time"
| summarize avg(CounterValue) by Computer, bin(TimeGenerated, 15m)
| render timechart

Qui where restringe a 24 ore e a un contatore specifico, summarize ... by bin() produce la media CPU per macchina ogni 15 minuti, render la visualizza. Questo è il pattern-tipo che l’esame propone come “grafico di andamento”.

Dalla query al log alert

Il passaggio critico: una log alert rule in Azure Monitor incapsula una query KQL eseguita a intervalli regolari. La configurazione ruota attorno a tre elementi:

  • Measure — la colonna numerica valutata (spesso il risultato di un summarize count() o avg()).
  • Aggregation granularity — la finestra temporale su cui la query aggrega.
  • Threshold + operatore — la condizione (es. count > 5) che, se soddisfatta, fa scattare l’alert collegato a un Action Group.

Esempio per rilevare VM che smettono di rispondere:

Heartbeat
| summarize LastSeen = max(TimeGenerated) by Computer
| where LastSeen < ago(5m)

La regola conta le righe risultanti; se il conteggio è maggiore di zero, esiste almeno una macchina silente da oltre 5 minuti. Nota: la regola definisce da sé la frequenza di valutazione, quindi nella query di allerta si evita di duplicare filtri temporali già gestiti dalla finestra della regola.

Trappole tipiche d’esame

  • Scenario: una query filtra where Computer == "web01" ma non restituisce righe, benché la VM esista. → Risposta: KQL è case-sensitive sui valori delle stringhe; se il record contiene WEB01, il confronto fallisce. Usa =~ (uguaglianza case-insensitive) o tolower().
  • Scenario: una query su un intervallo ampio è lentissima e costosa. → Risposta: manca un filtro where TimeGenerated > ago(...) in cima alla pipeline; senza restringere il range temporale si scansiona l’intera tabella. Filtra sempre il tempo per primo.
  • Scenario: serve individuare VM che non inviano più dati. → Risposta: interroga Heartbeat con summarize max(TimeGenerated) by Computer, non Perf; l’assenza di heartbeat è il segnale canonico di macchina down.
  • Scenario: serve un grafico di andamento della CPU nel tempo. → Risposta: aggrega con summarize ... by bin(TimeGenerated, ...) e chiudi con render timechart; senza bin() non ottieni serie temporali.
  • Scenario: occorre tracciare chi ha eliminato un resource group. → Risposta: la tabella è AzureActivity (control plane), filtrando su OperationNameValue e Caller, non le tabelle di performance del guest.