Useful Application Insights Log Analytics Kusto Queries

We use Azure’s Application Insights features as the performance monitoring tool on a lot of our apps.

These are some queries I’ve found that are useful for various troubleshooting situations

Filter logs

If you use Serilog or Microsoft’s ILogger and use the structured logging template, the placeholders in your log messages turn into customDimensions on the traces collection you can use to filter and group by.

For example _log.LogInformation("Customer {CustomerId} logged in", user.CustomerId) you can find traces:

1
2
3
4
traces
| where customDimensions.CustomerId == '1234'
| where timestamp > ago(24hr)
| order by timestamp desc

Filter logs by class

This assumes you use Serilog or Microsoft’s ILogger. It should set a SourceContext custom property on the log message which will let you filter:

1
2
3
traces
| where customDimensions.SourceContext contains "MyApp.SomeNamespace"
| project timestamp, customDimensions.SourceContext, message, operation_Id

Most common exceptions by endpoint

1
2
3
exceptions
| summarize count() by operation_Name, type
| order by count_ desc

Chattiest APIs

1
2
3
4
5
dependencies
| summarize count() by operation_ParentId
| join kind=inner requests on $left.operation_ParentId == $right.id
| order by count_ desc
| project timestamp, operation_Name, id, duration, db_queries=count_

Note that this is an expensive query, set a date range filter in the UI to reduce data processing costs

This counts “dependencies” per operation. In most of my apps, the dependencies are DB calls, but your app might include HTTP calls to downstream services. If so, you can filter the dependencies collection by | where type == 'SQL'

Count dependencies per request

If you have an operationId in hand, you can count the db calls with the count aggregate:

1
2
3
dependencies
| where operation_ParentId == '467e51e6b3343359'
| count

Find slowest call by Controller and Action

1
2
3
4
requests
| extend Action = extract(" (/api)?/([A-Za-z]+/[A-Za-z]+)", 2, name)
| summarize avg(duration), count(), percentiles(duration, 90, 95, 99) by Action
| order by avg_duration desc

This one assumes you have the default .NET controller routing, and all the names of your operations are something like api/Controller/Action. The extend operator uses extract to regex out the controller name and action name. This helps aggregate across different parameters. For example, if you have a bunch of operations that are like

  • GET api/Customer/Get/1234
  • GET api/Customer/Get/4230
  • GET api/Customer/Get/2566

This will aggregate them all under the Action name of just Customer/Get which averages across different specific customer resources.