// Illustrative; not executed against a live workspace. Azure Monitor Logs, resource-specific ApiManagementGatewayLogs. // Every route that answered in the last 30 days, to reconcile with your API register (step 1 of the guide). // Numbers and long IDs in paths become {id}, so one route is one row. UserId and ApimSubscriptionId are // API Management identities only; an empty value does not prove the application accepted an anonymous caller. let Start = ago(30d); let TargetResource = "REPLACE_WITH_APIM_RESOURCE_ID"; let RiskyRoute = @"(?i)/(v0|v1|old|legacy|test|stg|debug|internal|admin|mgmt|batch)(/|$)"; ApiManagementGatewayLogs | where TimeGenerated >= Start | where _ResourceId =~ TargetResource | extend Host = tostring(parse_url(Url).Host), Path = tostring(parse_url(Url).Path) | extend Route = replace_regex(Path, @"/[0-9A-Fa-f-]{8,}|/\d+", "/{id}") | summarize Requests = count(), Succeeded = countif(ResponseCode between (200 .. 299)), NoApimIdentity = countif(isempty(UserId) and isempty(ApimSubscriptionId)), Callers = dcount(CallerIpAddress), FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated) by Host, Method, Route, ApiId, OperationId | extend MatchedNoApi = isempty(ApiId), RiskyName = Route matches regex RiskyRoute | order by MatchedNoApi desc, RiskyName desc, Requests desc