APM Tips

KQL · exceptions

Unhandled vs handled exceptions

Split exceptions by the handledAt value your SDK records and by whether their request failed, the practical test of whether an exception escaped.

Updated

exceptionsrequests exceptions

let lookback = 24h;
let failedOperations = requests
    | where timestamp > ago(lookback)
    | where tostring(success) =~ "false"
    | distinct operation_Id;
exceptions
| where timestamp > ago(lookback)
| extend
    handled_at = iff(isempty(handledAt), "(empty)", handledAt),
    request_outcome = iff(operation_Id in (failedOperations), "request failed", "no failed request")
| summarize
    exceptions = sum(itemCount),
    types = dcount(type),
    example_type = take_any(type)
    by handled_at, request_outcome
| order by exceptions desc

Returns: One row per handledAt value and request outcome, with the sampling-adjusted exception count, the number of distinct exception types and one example type.

Pitfalls

  • Microsoft documents handledAt only as 'where the exception was seen'. Which values appear, and whether the column is filled at all, depends on the SDK, so read your own values before relying on them.
  • An exception in an operation whose request failed didn't necessarily cause the failure, and one in a successful operation may still have been logged as an error. The split is a strong hint, not a proof.
  • Exceptions from background work have no request, so they land in 'no failed request' whatever happened.
  • The in operator reads up to 1,000,000 distinct values from the tabular expression. On a very busy resource with a long lookback, shorten the window.

How it works

The data model says an exception item represents “a handled or unhandled exception”, but the schema doesn’t give you a clean yes-or-no column for which. The classic handledAt column (HandledAt in the workspace) is described only as where the exception was seen, and SDKs differ in whether and how they fill it. So this query looks at the question from two sides: what the SDK recorded, and what happened to the request.

Line by line

  • let failedOperations = ...; lists the operation_Id of every failed request in the window. distinct keeps one row per ID.
  • handled_at shows the recorded handledAt value, with empty values labelled so they are visible as a row of their own.
  • request_outcome uses in with the tabular expression to test whether the exception’s operation contains a failed request. An exception that escaped your handlers usually ends the request with a failure; one your code caught and tracked usually doesn’t.
  • exceptions = sum(itemCount) counts exceptions the sampling-aware way; types and example_type show how varied each group is.

Reading the result

The “request failed” rows are the exceptions users felt. If the classic SDK’s exception tracking modules are on (the web module tracks unhandled exceptions in web apps; the Windows Server modules track unhandled and unobserved task exceptions in services and console apps), most escaped exceptions land there. A large “no failed request” group is the opposite: exceptions your code caught, tracked and survived. They are cheap to ignore and expensive to store; the pricing guide covers why volume matters.

Where handled_at has meaningful values for your SDK, compare them with the request outcome. The two should broadly agree; where they don’t, look at a few rows with exception details for a problem ID. The ASP.NET MVC and Web API guide explains which unhandled exceptions the classic SDK captures for you on .NET Framework.

Variations

  • Which SDK fills the column: add sdkVersion to the by clause.
  • What else is recorded: run exceptions | take 20 | project customDimensions to see the properties your SDK attaches, and group by one that marks handled exceptions if it has one.
  • Workspace tables: use AppExceptions and AppRequests, TimeGenerated, HandledAt, OperationId, ExceptionType, Success and ItemCount.

Sources, checked

  1. Azure Monitor Logs reference - AppExceptions (HandledAt)learn.microsoft.com · checked
  2. Application Insights telemetry data model (handled or unhandled exceptions)learn.microsoft.com · checked
  3. Application Insights Classic API 2.x (exception tracking modules)learn.microsoft.com · checked
  4. The case-sensitive in string operator (Kusto)learn.microsoft.com · checked
  5. Migrate an Application Insights classic resource to a workspace-based resource (table schemas)learn.microsoft.com · checked