Since the last lesson, the Kladde writes traces, logs and custom measurements to its workspace in Azure. The Application Insights views show the usual things from it. For everything else, you ask questions in a language of its own: KQL, the Kusto Query Language. With it you query Log Analytics and Application Insights, Azure Resource Graph from lesson 3.1.6 and Microsoft's security tools. The alerts of the next lesson are KQL queries, too.

KQL only reads. A query cannot change or delete anything, so you can try things out without risk. In this lesson you learn the most important building blocks, a trap that makes a whole query worthless without anyone noticing, and how the Kladde's queries get into the repository as files, with a test.

Where you ask

In the portal there are two doors to the same data:

  • Application Insights → Logs. Here the tables are named as they used to be: requests, dependencies, traces, exceptions, customMetrics.
  • Log Analytics workspace → Logs. Here they are named AppRequests, AppDependencies, AppTraces, AppExceptions, AppMetrics, and next to them are the logs of the Container Apps environment.

The columns are named differently in the two worlds:

Workspace (AppRequests …) classic (requests …) Content
TimeGenerated timestamp point in time
AppRoleName cloud_RoleName role name of the service
Name name name of the request or dependency, such as GET /appointments
DurationMs duration duration in milliseconds
Success, ResultCode success, resultCode success and status code
OperationId operation_Id trace ID of the trace
ItemCount itemCount how many events the row stands for
Properties customDimensions attributes of the span or fields of the log line
Target, DependencyType target, type target and kind of a dependency

The Kladde writes all queries against the workspace. That is also where the console logs of the Container Apps live, and where the alerts run later. Queries from tutorials on the web often use the classic names; with the table above you translate them.

The result of every query depends on the time range. If the query itself contains a filter on TimeGenerated, that one applies; otherwise the range you choose at the top of the portal. Write the time range into the query: Then it returns the same in the portal, in a script and in an alert.