APM Tips

KQL · exceptions

Exceptions by type and operation

Count exceptions in the last 24 hours by exception type and operation, sampling-adjusted, with one outer message and the innermost type for each.

Updated

exceptions exceptions

let lookback = 24h;
exceptions
| where timestamp > ago(lookback)
| summarize
    exceptions = sum(itemCount),
    problems = dcount(problemId),
    example_message = take_any(outerMessage),
    innermost_type = take_any(innermostType)
    by type, operation_Name
| top 50 by exceptions desc

Returns: Up to 50 rows, one per exception type and operation, with the sampling-adjusted count, the number of distinct problem IDs, one outer message and one innermost exception type.

Pitfalls

  • Exceptions thrown outside a request (startup, background work, timers) have an empty operation_Name and group together in one row per type.
  • Count with sum(itemCount): with sampling on, each stored exception can stand for several.
  • The workspace name for the classic type column is ExceptionType, not Type: in AppExceptions, Type is the table name.
  • A type such as System.Exception or Error says little on its own. The problems column shows whether one throw site or many are behind the count.

How it works

The Failures view in the portal ranks exceptions for you, but a query lets you rank them your way and keep the answer. This one is the starting point for any exception review: what is thrown, where, and how often.

Line by line

  • let lookback = 24h; sets the window.
  • exceptions = sum(itemCount) counts exceptions the sampling-aware way. Microsoft’s own example for counting exceptions by type uses summarize sum(itemCount) by type for the same reason.
  • problems = dcount(problemId) counts distinct problem IDs. The data model describes problemId as identifying where in code the exception was thrown, typically the type plus a function from the call stack. One type with ten problem IDs is ten different bugs that happen to share an exception class.
  • example_message = take_any(outerMessage) keeps one message of the outer exception, and innermost_type keeps the type at the bottom of the chain. When a framework wraps everything in its own exception, the innermost type is usually the real cause.
  • by type, operation_Name groups by exception type and by the operation that was running.
  • top 50 by exceptions desc keeps the 50 largest rows.

Reading the result

Read the top rows for volume, then scan for exceptions in operations where you didn’t expect any. High-volume exceptions in a healthy route are often caught and handled on purpose, such as a cache miss implemented with an exception or a cancelled request; they cost ingestion and hide new problems, so consider not tracking them. To see which ones break requests, use failed requests joined to their exceptions, and take any problem into exception details for a problem ID.

Which exceptions reach this table at all depends on the SDK and on what your code tracks. The ASP.NET MVC and Web API guide covers the classic .NET Framework case, and the logging guide explains how a log call with an exception lands here instead of in traces.

Variations

  • By service: add cloud_RoleName to the by clause.
  • Trend: group by bin(timestamp, 1h), type, keep the count, sort by timestamp and add | render timechart.
  • Workspace tables: use AppExceptions, TimeGenerated, ExceptionType, ProblemId, OuterMessage, InnermostType, OperationName and ItemCount.

Sources, checked

  1. Application Insights telemetry data model (exception fields)learn.microsoft.com · checked
  2. Azure Monitor Logs reference - AppExceptionslearn.microsoft.com · checked
  3. Application Insights Classic API 2.x (exceptions in Log Analytics)learn.microsoft.com · checked
  4. top operator (Kusto)learn.microsoft.com · checked
  5. Migrate an Application Insights classic resource to a workspace-based resource (table schemas)learn.microsoft.com · checked