Create a link to an Application Insights query programmatically

In our telemetry session at Directions EMEA in Milan we have presented how you can directly use Dynamics 365 Business Central to monitor its telemetries. We actually use this technique in many real-world projects and for one of them we’re doing something more in these days:

  • We automatically send telemetry reports to administrators via email.
  • We provide a link on the report to directly show the Application Insights queries in the Azure Portal when needed.

I plan to show these things in details in a serie of partner’s trainings planned by the Microsoft Western Europe PTS Team starting from February (so check your mailbox in the upcoming weeks), but in thist post I want to give you more details about the last point listed above.

There are situations where could be interesting to provide a link to an Application Insights query (written in KQL) to your administrators to continue investigating some telemetry reports. By clicking this link, you will be automatically connected to the Azure Portal in the right Application Insight instance and the query is executed for you.

To quickly show what I mean, imagine that I want to execute this KQL query:

traces
| summarize RequestCount=sum(itemCount) by bin(timestamp,60m)
| render timechart

This query creates a time chart of the requests injected by our tenant to Application Insights every hour in a selected period of time:

From the query editor, you can select the Share button and then click on Copy link to query in order to have a direct link to your Application Insights query:

The url generated from this action has the following format:

https://portal.azure.com/#@TENANT_ID/blade/Microsoft_Azure_Monitoring_Logs/LogsBlade/resourceId/%2Fsubscriptions%2FSUBSCRIPTION_ID%2FresourceGroups%2FRESOURCEGROUP%2Fproviders%2Fmicrosoft.insights%2Fcomponents%2FAPPINSIGHTS_INSTANCE_NAME/source/LogsBlade.AnalyticsShareLinkToQuery/q/ENCODED_KQL_QUERY/timespan/TIMESPAN

I’ve emphasized in bold here the parameters of the url. These parameters have the following values:

  • TENANT_ID: ID of your Azure AD Tenant (where your Azure Application Insights instance lives).
  • SUBSCRIPTION_ID: ID of the Azure Subscription that contains the Application Insights instance.
  • RESOURCE_GROUP: name of the Resource Group where the Application Insights instance is deployed.
  • APPINSIGHTS_INSTANCE_NAME: Name of the Application Insights instance.
  • ENCODED_KQL_QUERY: encoded KQL query to execute (details below).
  • TIMESPAN: time filter for the query (optional).

As you can see, it’s quite asy to dinamically generate a direct url for your KQL queries. But what about the ENCODED_KQL_QUERY parameter?

The ENCODED_KQL_QUERY parameter must contain the Base64 encoding of your query text zipped and URL encoded/escaped. In the above example, my query url is something like the following:

https://portal.azure.com#@TENANT_ID/blade/Microsoft_Azure_Monitoring_Logs/LogsBlade/resourceId/%2Fsubscriptions%2FSUBSCRIPTION_ID%2FresourceGroups%2Fd365bctelemetryrg%2Fproviders%2Fmicrosoft.insights%2Fcomponents%2Fd365bctelemetry/source/LogsBlade.AnalyticsShareLinkToQuery/q/H4sIAAAAAAAAAyspSkxOLeaqUSguzc1NLMqsSlUISi0sTS0ucc4vzSuxBQprZJak5oJ5mgpJlQpJmXkaJZm5QBWJuQU6Zga5mkDdRal5KalFCiDx5IzEohIAEBQGxlcAAAA%253D/timespan/2021-12-12T07%3A34%3A15.000Z%2F2022-01-11T07%3A34%3A15.819Z

If your query has less than 1600 characters, you can also replace the q parameter in the above url by a query parameter and the encoded string will simply be your query plain text escaped (without zipping and encoding).

As you can see, to correctly generate this dynamic url it’s important to:

  • Take the text of your KQL query
  • Zip it
  • Encode it in Base64

A C# code that does the encoding of the KQL query is the following:

static string EncodedKQLQuery(string query)
{
    var bytes = System.Text.Encoding.UTF8.GetBytes(query);
    using (MemoryStream memoryStream = new MemoryStream())
    {
        using (GZipStream compressedStream = new GZipStream(memoryStream, CompressionMode.Compress, leaveOpen: true))
        {
            compressedStream.Write(bytes, 0, bytes.Length);
        }
        memoryStream.Seek(0, SeekOrigin.Begin);
        Byte[] data = memoryStream.ToArray();
        string encodedQuery = Convert.ToBase64String(data);
        return HttpUtility.UrlEncode(encodedQuery);
    }
}

In this way you can programmatically generate urls for your KQL queries. When you have the link you can click on it and (if you have the permissions to access the Application Insights resource) the query is immediately executed with the right parameters:

With just a click you’re redirected to the right Application Insights instance and you can inspect results starting from your query results.

NOTE: Inmy above sample query I’ve placed fixed dates as TIMESPAN parameter. TIMESPAN values can also be hardcoded as follows:

  • PT30M : 30 minutes
  • P1D: 1 day
  • P1W: 1 week
  • P1M: 1 month

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.