Sep 102018
 September 10, 2018  Posted by at 10:34 am Azure Log Analytics  Add comments

I seem to be writing a lot about Application Insights lately, but I swear I do other things than write queries against our resources. We have application implementations consultants for our product, Konstrukt, and they each take care of several tenants. It would be very beneficial for them to be able to see errors happening in the system as they are configuring a tenant, and our logs that are unified in Azure is a great place to access those errors. I’ve put together some queries that show the errors, the tenant, user session and id, and timestamp. However, navigating around in the portal isn’t their favorite thing to do, so I decided to set aside a few hours last Friday and through together a web service (ASP.NET Core of course) that shows the errors.

Application Insights has a REST API, but the documentation is lacking a little bit at the moment, and one of the things that weren’t clear was how to do queries across resources.

As I blogged about earlier (and there is a video as well), you can query across resources by using the app() function and pass in the resource name or id (a GUID) and do a union on them. The problem is that the REST API lets you authenticate in two ways, the recommended way is by using an Application Insights resource API key specific for that one resource, or by using Active Directory (which has quite a few steps as you need to set up the AD and tie the resources to it and so on). I couldn’t figure out how to use API keys (preferred as revoking a key is easy in case of a security breach), and saw that somebody else had the same issue on StackOverflow.

I’m not going to lie, it took a while before I was able to get it working, but with the help from the comments from John Gardner I was able to piece a solution together.

Here is an example with the query in the body. My queries are quite complex and have a lot of let statements and therefore passing the query in the body is easier. There are some PowerShell quirks in the example below, but I’ll update with a C# example tomorrow.

The let statement in the example below is pretty pointless, it’s mostly there to show that you can do complex queries with let expressions etc.
AppId is the Application Insights resource ID – and NOT the instrumentation key. The API key is just a long string and you can create up to 10 of them AFAIK.

You will find both the id and keys under API Access (I’ve added a screenshot as it’s easy to get them confused). When you use the app() function use the app id or name.


$app1Id = "GUID"
$app2Id = "GUID"

$app1Key = "string"
$app2Key = "string"

# EXAMPLE: "X-Api-Key" = "key1:GUID1,key2:GUID2"
$headers = @{ "X-Api-Key" = "${app1Key}:$app1Id,${app2Key}:$app2Id"; "Content-Type" = "application/json" }

# EXAMPLE: "query" = "union app('GUID1').something, app('GUID2').something | limit 5"
$query = @{"query" = "let days=1d;union app('$app1Id').exceptions,app('$app2Id').exceptions | where timestamp > ago(days)"}
$body = ConvertTo-Json $query | % { [regex]::Unescape($_) }

$result = Invoke-RestMethod "$app1Id/query" -H $headers -Body $body -Method POST

The query above will return all the exceptions for the two Application insights resources for the last day. You can do a query across 10 resources at the time of writing, 200 requests per 30 seconds or a max of 86,400 requests per day (UTC). Other limits apply if you use ADD.

NOTE: the extra {} in the header is a PowerShell quirk in regards to variables and the use of the colon char, and as you can see in the example you should not bracket the keys in the header 🙂

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>



What is 11 + 6 ?
Please leave these two fields as-is:
IMPORTANT! To be able to proceed, you need to solve the following simple math (so we know that you are a human) :-)