Hello! Welcome to the next lesson in our module on monitoring and troubleshooting distributed applications.
In our last session, you learned how to enrich your application's telemetry by sending custom events and metrics using the Application Insights SDK. You now have a rich dataset describing not just the performance of your app, but also its business-level operations.
Today, we will address the learning outcome: Write foundational Kusto Query Language (KQL) queries to analyze telemetry data. This is the key to unlocking the insights buried within the terabytes of data that Application Insights and Azure Monitor collect. KQL is the language you'll use to search for specific errors, calculate custom performance indicators, and build powerful visualizations.
Given your extensive background in SQL, you will find many familiar concepts in KQL, such as filtering, projecting, and aggregating data. However, KQL has a unique "pipeline" syntax that is exceptionally well-suited for exploring time-series data like logs and metrics.
1. Introduction to Kusto Query Language (KQL)
Before we start writing queries, let's get a high-level overview of what KQL is and where it fits into the Azure ecosystem. It's a powerful, read-only query language designed for analyzing large volumes of structured, semi-structured, and unstructured data.
Kusto Query Language (KQL) Overview
To start, watch this introductory segment from John Savill's Technical Training. It provides an excellent overview of what KQL is, the types of data it can query, and the various Azure services that use it.
Watch from the beginning to 04:38. Focus on understanding that KQL is a unified language for many Azure services, including Log Analytics (which powers Application Insights), Azure Resource Graph, and Azure Data Explorer.
As the video explains, services like Application Insights are built on top of a powerful backend that uses KQL. We will be writing our queries in the Log Analytics workspace associated with your Application Insights resource.

For practice, we'll use the official Azure Log Analytics demo environment, which is pre-populated with sample data. You can access it here: https://aka.ms/lademo. Open this in a new tab to follow along with the exercises.
2. Foundational KQL Syntax: The Pipeline Model
The fundamental structure of a KQL query is a pipeline. You start with a data source (a table) and then pipe (|) its output through a series of operators that filter, shape, and aggregate the data.
TableName | operator1 | operator2 | ...
This is different from SQL's SELECT ... FROM ... WHERE structure but is incredibly intuitive for data exploration.
Get started with log queries in Azure Monitor Logs
Let's read the official Microsoft Learn documentation to understand the basic building blocks of a KQL query. This document is focused on querying logs in Azure Monitor, which is exactly what we're doing.
Please read the following sections: Structure a query: Focus on the 'Table-based queries' part. Note the emphasis on starting with a table name and the fact that KQL is case-sensitive. The pipe character and the take operator: The section explains how to get a small, random sample of data, which is essential for initial exploration. project operator: Read the first part of 'Include or exclude columns in query results' to learn how to select, rename, and create new columns.
Let's summarize the key operators from the reading:
|(pipe): Separates commands, passing the output of the previous command as the input to the next.take <number>: Returns a specified number of arbitrary rows. This is great for quickly sampling data without performance-heavy sorting. It's like SQL'sTOP Nbut without a guaranteed order.project <columns>: Selects the columns you want to see, similar to theSELECTclause in SQL. You can also use it to rename columns (NewName = OldName) and create simple calculated columns.
Practice Exercise 1 (5 minutes)
Go to the Log Analytics demo environment. In the query editor, run the following queries. Observe how the pipeline refines the data at each step.
- Start by looking at the raw
requeststable (the UI will automatically limit results):requests - Now, get a small sample of 10 records:
requests | take 10 - Finally, select and rename a few specific columns from that sample:
requests | take 10 | project RequestTime = timestamp, HttpMethod = client_Method, Url = url, ResponseCode = resultCode
3. Filtering and Sorting Data
Just like in SQL, the most common operations are filtering data to find what you need and then ordering it.
where <condition>: This is KQL's equivalent of theWHEREclause in SQL. It filters rows based on a boolean expression.- Time Filters: Since you're working with telemetry, filtering by time is crucial for performance and relevance. The
ago()function is a common way to do this (e.g.,timestamp > ago(1h)for data from the last hour). top <number> by <column>: Sorts the entire dataset by a specific column and returns the top N records. This is more efficient than usingsortand thentake.sort by <column> [asc | desc]: Sorts the entire result set. Use this when you need all the data sorted, not just the top records.
Get started with log queries in Azure Monitor Logs
Let's return to the Microsoft Learn document to see how to implement filtering and sorting.
Please read the following sections: Filter results: This covers the where operator. Pay close attention to the table of comparison expressions (like ==, !=, ~= for case-insensitive equality). Specify a time range: This is a critical section that explains how to use the time picker and, more importantly, how to add a time filter like ago() directly into your query. Sort results: This explains the sort and top operators.
Best Practice: Always place your time filter (where timestamp > ...) as early as possible in the query pipeline, right after the table name. This dramatically reduces the amount of data the subsequent operators have to process.
Practice Exercise 2 (5 minutes)
In the demo environment, let's build a query to find the 5 slowest successful requests from the last day.
requests
| where timestamp > ago(1d) // Filter to the last 24 hours
| where success == true // Filter for successful requests
| top 5 by duration desc // Find the 5 slowest (highest duration)
| project timestamp, url, duration
Notice the order: we filter the dataset down to a smaller, relevant set of rows before performing the more expensive top operation.
4. Aggregating and Calculating Data
Exploring individual log entries is useful, but the real power comes from aggregation—summarizing data to spot trends.
summarize <aggregation> by <column>: This is KQL's version ofGROUP BY. It groups rows that have the same values in thebycolumn and then computes an aggregation over each group.- Common aggregations:
count(),dcount()(distinct count),avg(),sum(),min(),max(),percentiles().
- Common aggregations:
extend <NewColumn> = <expression>: Adds a new column to the result set while keeping all existing columns. This is useful for performing calculations on a per-row basis.bin(<column>, <size>): A powerful function often used withsummarize. It groups a continuous value (like a timestamp or a number) into buckets of a specified size. For example,bin(timestamp, 1h)groups all timestamps into the hour they belong to.render <charttype>: A special operator that visualizes the results. It must be the last command in the pipeline. Common types aretimechart,piechart, andbarchart.
To see these powerful operators in action, let's watch a few more clips.
Kusto Query Language (KQL) Overview
This set of clips from John Savill demonstrates aggregation, calculation, and time-based charting.
Watch the following segments: Summarize (19:56 - 20:50): A quick demo of using summarize count() by to count events by type. Extend and Sort (20:50 - 22:26): Shows how to use extend to create a new calculated column (duration) and then sort by it. Time Binning (49:10 - 56:09): This is a key segment. It shows how to extract parts of a datetime, use bin() to group data into hourly buckets, summarize the count for each bucket, and finally use render timechart to create a powerful visualization.
Practice Exercise 3 (5 minutes)
Let's write a query that embodies a very common monitoring pattern: counting the number of requests per hour over the last 24 hours and displaying it as a time chart.
In the demo environment, run this query:
requests
| where timestamp > ago(24h)
| summarize count() by bin(timestamp, 1h)
| render timechart
This single query gives you a 24-hour trend chart of your application's traffic. Now, try changing it to count failed requests (where success == false) or to see the average duration per hour (summarize avg(duration) by bin(timestamp, 1h)).
Conclusion
In this lesson, you've learned the fundamentals of the Kusto Query Language, giving you the power to transform raw telemetry data into actionable insights.
Key Takeaways:
- KQL uses a pipeline syntax (
|) to chain operators together, making it ideal for interactive data exploration. - Always start queries with a table name and filter by time as early as possible.
- Use
taketo sample data,projectto select columns, andwhereto filter rows. - Use
topandsortto order your results efficiently. - Use
summarizeto perform aggregations (like SQL'sGROUP BY) andextendto create new calculated columns. - Combine
summarizewithbin()andrender timechartto easily create time-series visualizations.
As a final takeaway, here is a handy cheat sheet that summarizes many of the operators we've discussed today.
Next Steps
Now that you can write queries to find specific metrics or error conditions in your logs, the next logical step is to automate this process. In our next lesson, you will learn how to create alert rules in Azure Monitor that run KQL queries on a schedule and notify you when certain thresholds are breached.