Overview and What You Will Learn
In this lab, you will send VM logs into a Log Analytics Workspace, then write a series of KQL queries - starting simple and adding filtering and summarization - to go from "here is a huge pile of raw log data" to "here is exactly which error happened, how often, and when."
Why This Matters in Production
An engineer at a growing e-commerce platform is told "checkout is slow sometimes," with no more specific information than that. Without the ability to actually query logs - filtering by time range, error type, and frequency - finding the actual root cause becomes a matter of scrolling through raw text files by hand. KQL turns that into a precise, repeatable question asked directly against the data.
Core Principles
KQL queries are built as a pipeline - each step, separated by a pipe character, narrows or reshapes the data before passing it to the next step.
+------------------------------------------+| Start with a table (e.g. Heartbeat, || Syslog, AppExceptions) |+------------------------------------------+ | v+------------------------------------------+| Filter rows (where clause) |+------------------------------------------+ | v+------------------------------------------+| Reshape or summarize (project, summarize) |+------------------------------------------+ | v+------------------------------------------+| Sort and limit results |+------------------------------------------+Reading a KQL query top to bottom tells you exactly what's happening to the data at each stage - this pipeline structure is what makes even a complex query readable once you know to look for it.
Detailed Step-by-Step Practical Lab
- Create a Resource Group and a Log Analytics Workspace:
az group create --name rg-kql-lab-mumbai --location centralindia az monitor log-analytics workspace create \ --resource-group rg-kql-lab-mumbai \ --workspace-name law-kql-lab- Create a VM and connect it to send logs into this workspace:
az vm create \ --resource-group rg-kql-lab-mumbai \ --name vm-kql-lab \ --image Ubuntu2204 \ --size Standard_B1s \ --admin-username azureadmin \ --generate-ssh-keys # on this VM and configured to send logs to the workspace created above- Once logs are flowing, start with the simplest possible query - just look at recent entries from a table:
Heartbeat| take 10- Narrow the query to a specific time range and computer name using
where:
Heartbeat| where TimeGenerated > ago(1h)| where Computer == "vm-kql-lab"- Reshape the results to show only the specific columns that matter, using
project:
Heartbeat| where TimeGenerated > ago(1h)| project TimeGenerated, Computer, OSType- Summarize how many heartbeats were received per hour, to spot any gaps in reporting:
Heartbeat| where TimeGenerated > ago(24h)| summarize count() by bin(TimeGenerated, 1h)| order by TimeGenerated ascNote
bin(TimeGenerated, 1h)groups timestamps into 1-hour buckets before counting - this is the standard KQL pattern for building a time-series view of any metric, like errors per hour or requests per minute.
- Search across the Syslog table for any lines containing the word "error," a common first step when investigating an unspecified problem:
Syslog| where TimeGenerated > ago(6h)| where SyslogMessage contains "error"| project TimeGenerated, Computer, SyslogMessage| order by TimeGenerated desc- Clean up:
az group delete --name rg-kql-lab-mumbai --yes --no-waitProduction Best Practices & Common Pitfalls
Common MistakeWriting a query with no time filter at all against a workspace collecting months of data. This can be slow and expensive to run, and usually returns far more results than are actually useful - always start with a
where TimeGenerated > ago(...)filter before adding anything else.
TipBuild a query incrementally - start with
take 10to see what the raw data looks like, then addwherefilters one at a time, checking results after each addition, rather than trying to write the complete, complex query in one attempt.
summarizeis the tool for turning raw log rows into an actual answer - "how many," "average of what," "grouped by which field" are all summarize-shaped questions, distinct from filtering, which only narrows which raw rows you see.- Save frequently used queries rather than rewriting them from scratch during every incident. A saved query for "show me all errors in the last hour for this specific service" turns a repeatable investigation into a single click.
Quick Reference & Troubleshooting Commands
| KQL Operator | Description |
|---|---|
where |
Filter rows based on a condition |
project |
Select and reshape specific columns |
summarize |
Aggregate rows (count, average, etc.) |
order by |
Sort results |
take N |
Return only the first N rows, useful for quick previews |
ago(1h) |
A relative time reference, here meaning "1 hour ago" |