KQL · latency
Request latency p50, p95 and p99 by cloud role
Compare median, p95 and p99 request duration across the services that share one Application Insights resource, weighted for sampling, slowest first.
requests latency
let lookback = 24h;
requests
| where timestamp > ago(lookback)
| summarize
requests = sum(itemCount),
p50_ms = percentilew(duration, itemCount, 50),
p95_ms = percentilew(duration, itemCount, 95),
p99_ms = percentilew(duration, itemCount, 99)
by cloud_RoleName
| order by p95_ms desc Returns: One row per cloud role name with its request count and its p50, p95 and p99 duration in milliseconds, slowest p95 first.
Pitfalls
- Services that don't set a cloud role name can share one value, or arrive with an empty one, and collapse into a single row. Set the role name in every service that sends to the resource.
- A service with a few hundred requests a day produces a noisy p99. Read p99 only for roles with enough traffic, or add | where requests > 1000.
- Each role's numbers mix all its routes. A fast health-check endpoint called every few seconds can pull a role's p50 down; filter it out by operation_Name.
- Separate Application Insights resources don't appear here: this query reads one resource. Use a cross-resource query to compare services that send to different resources.
How it works
When several services send telemetry to one Application Insights resource, the first latency question is “which service?”. The cloud_RoleName column answers it: it is the name each service reports for itself, the same name Application Map uses for its nodes.
Line by line
let lookback = 24h;sets the window; change it in one place.where timestamp > ago(lookback)keeps requests that started in the window (UTC).requests = sum(itemCount)counts requests the sampling-aware way. A stored row withitemCount4 stands for four requests.percentilew(duration, itemCount, N)gives the median, p95 and p99 ofdurationin milliseconds, each row weighted by the requests it stands for.by cloud_RoleNamemakes one row per service.order by p95_ms descputs the service that is slow for one user in twenty at the top.
Reading the result
Compare the roles to each other and to themselves over time. A front-end role is usually slower than the APIs it calls, because its duration includes theirs. A back-end role with a p95 close to its caller’s p95 is where the time goes. A role whose p99 sits far above its p95 has a tail problem: timeouts, cold starts, or a lock that one request in a hundred waits on.
If the role names look wrong (one row called after the process, or two services in one row), fix the names before trusting the numbers. The correlation and Application Map guide explains what the role name is for, and the initializers and processors guide shows how to set it in the classic SDK and in OpenTelemetry.
Variations
- Drill into one role: add
| where cloud_RoleName == "orders-api"and group byoperation_Nameinstead, which is the per-operation query. - Per role over time: group by
bin(timestamp, 1h), cloud_RoleName, keep one percentile, sort bytimestampand add| render timechart. - Per instance: add
cloud_RoleInstanceto thebyclause to see whether one machine or container is slower than its siblings. - Workspace tables: use
AppRequests,TimeGenerated,DurationMs,ItemCountandAppRoleName(the classiccloud_RoleName).