Skip to content

Commit

Permalink
Sample that creates Application Insights URL's based on botConfiguration
Browse files Browse the repository at this point in the history
  • Loading branch information
daveta committed Dec 27, 2018
1 parent ab76c0e commit 8768e62
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 0 deletions.
98 changes: 98 additions & 0 deletions makeAppInsightsUrl/ExportQueryHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
using Microsoft.Bot.Configuration;
using System;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Text;

namespace makeAppInsightsUrl
{

/// <summary>
/// Application Insights Export Query Helper.
/// </summary>
class ExportQueryHelper
{
private readonly BotConfiguration _botConfig;
private readonly AppInsightsService _appInsights;

// URL constants
private const string PortalDomainName = "ms.portal.azure.com";
private const string Options = "/isQueryEditorVisible/true";
private const string BladeIdentifier = "/blade/Microsoft_OperationsManagementSuite_Workspace/AnalyticsBlade";
private const string Initiator = "/initiator/AnalyticsShareLinkToQuery";

/// <summary>
/// Initializes the Application Insights Query helper with appropriate metadata.
/// </summary>
/// <param name="botConfig">The BotConfiguration for the bot.</param>
/// <param name="appInsightsInstance">[Optional] Identifies an Application Insights instance name to use within the Bot Configuration.</param>
public ExportQueryHelper(BotConfiguration botConfig, string appInsightsInstance = null)
{
_botConfig = botConfig ?? throw new ArgumentNullException(nameof(botConfig));

if (!string.IsNullOrWhiteSpace(appInsightsInstance))
{
_appInsights = (AppInsightsService)botConfig.Services.Find(x => x.Name == appInsightsInstance && x.Type == ServiceTypes.AppInsights)
?? throw new InvalidOperationException($"Application Insights `{appInsightsInstance}` not found in bot configuration.");
}
else
{
_appInsights = (AppInsightsService)botConfig.Services.Find(x => x.Type == ServiceTypes.AppInsights)
?? throw new InvalidOperationException("No Application Insights resource found in bot configuration.");
}

// Add AAD tenant ID only if it is a valid Guid
Guid aadTenantGuid;
if (!Guid.TryParse(_appInsights.TenantId, out aadTenantGuid))
{
throw new InvalidOperationException("Application Insights tenant ID is invalid");
}
}

/// <summary>
/// Builds a URL that brings up Application Insights "Logs" blade and pre-populates query.
/// </summary>
/// <returns>A URL that brings up Application Insights "Logs" blade with pre-populated query.</returns>
public string BuildNavigationUrl(string query)
{
// Build uri of correct format.
string portalUri = $"https://{PortalDomainName}#@{_appInsights.TenantId}";
portalUri += string.Format(CultureInfo.InvariantCulture, BladeIdentifier + Initiator + Options + Scope() + Query(query));
return portalUri;
}

// Encode the query
private string Query(string query)
{
return ($"/query/{ WebUtility.UrlEncode(CompressAndEncode(query)) }/isQueryBase64Compressed/true");
}

// Resource scope definition
private string Scope()
{
return $"/scope/" + WebUtility.UrlEncode("{\"resources\":[{\"resourceId\":\"" + ResourceId() + "\"}]}");
}

// Gzip compress and then base64 encode text
private string CompressAndEncode(string text)
{
var bytes = Encoding.UTF8.GetBytes(text);
using (var memoryStream = new MemoryStream())
{
using (var zipStream = new GZipStream(memoryStream, CompressionMode.Compress))
{
zipStream.Write(bytes, 0, bytes.Length);
}
return System.Convert.ToBase64String(memoryStream.ToArray());
}
}

// Resource ID embedded in the scope.
private string ResourceId()
{
return $"/subscriptions/{_appInsights.SubscriptionId}/resourcegroups/{_appInsights.ResourceGroup}/providers/microsoft.insights/components/{_appInsights.ServiceName}";
}
}
}
24 changes: 24 additions & 0 deletions makeAppInsightsUrl/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;
using Microsoft.Bot.Configuration;
using Microsoft.Extensions.Configuration;

namespace makeAppInsightsUrl
{
class Program
{
/// <summary>
/// Demonstrates how to make a Application Insights portal query pre-populate.
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
BotConfiguration botConfig = BotConfiguration.Load("sample.bot");
ExportQueryHelper queryHelper = new ExportQueryHelper(botConfig);
var query = "This is a new query!";

Console.WriteLine(queryHelper.BuildNavigationUrl(query));
Console.WriteLine("Done!");

}
}
}
20 changes: 20 additions & 0 deletions makeAppInsightsUrl/makeAppInsightsUrl.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.2</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Bot.Configuration" Version="4.2.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.2.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
</ItemGroup>

<ItemGroup>
<None Update="sample.bot">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
20 changes: 20 additions & 0 deletions makeAppInsightsUrl/sample.bot
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "sample",
"description": "",
"services": [
{
"type": "appInsights",
"tenantId": "00000000-0000-0000-0000-000000000000",
"subscriptionId": "00000000-0000-0000-0000-000000000000",
"resourceGroup": "sample",
"name": "sample",
"serviceName": "sample",
"instrumentationKey": "00000000-0000-0000-0000-000000000000",
"applicationId": "00000000-0000-0000-0000-000000000000",
"apiKeys": {},
"id": "4"
}
],
"padlock": "",
"version": "2.0"
}

0 comments on commit 8768e62

Please sign in to comment.