Thursday, 28 May 2015

Adventures in Application Insights - Part 1

If, like I was, you’re struggling to get anything out of Azure Application Insights, I hope to be of some help.

It all started well enough – I added App Insights to a web app, this setup the ApplicationInsights.config file for me and boom, I had some data in App Insights on the web. Then I wanted to write a custom event to the cloud so I added the following code into the app…

  var tc = new TelemetryClient();
  tc.TrackEvent("Testing");
  tc.Flush();

I ran my app and imagine my dismay when nothing happened. I checked around in blog posts, looked at the official documentation, tried a bunch of things – but stubbornly the above lines of code simply didn’t want to work for me.

Instrumenting a Console App

The web project I’m adding this to isn’t the simplest, so rather than hack it around too much I then decided to create a simple Console App and debug through it to see what was happening. Here it is in its entirety…

using Microsoft.ApplicationInsights;
namespace ConsoleApplication3
{
    class Program
    {
        static void Main(string[] args)
        {
            var tc = new TelemetryClient();
            tc.TrackEvent("Testing");
            tc.Flush();
        }
    }
}

Not a great deal going on there! Having seen the ApplicationInsights.config file in the other project I added one to my console app too – well, I copied it from the web app to be fair. I ran the app and once again – nothing. At that point I decided it was time to do some debugging – but I couldn’t find symbols for Microsoft.ApplicationInsights.dll (and others from the App Insights stable), so I dragged out my trusty copy of Reflector and created some. If you didn’t already know, Reflector can generate missing PDB’s for you, it’s cooler than a penguins chilly bits and well worth the cost.

With a .pdb in hand I then stepped into the TrackEvent method and further down the call chain until I got to this point in the code…

[EditorBrowsable(EditorBrowsableState.Never)]
public void Track(ITelemetry telemetry)
{
  if (this.IsEnabled()
  {
    string instrumentationKey = this.Context.InstrumentationKey;
    if (string.IsNullOrEmpty(instrumentationKey))
    {
      instrumentationKey = this.configuration.InstrumentationKey;
    }
    if (!string.IsNullOrEmpty(instrumentationKey))
  ...

When I inspected the instrumentationKey it was empty - and this indicated to me that despite having an ApplicationInsights.config file, this wasn't actually being picked up. A quick look on disk and I saw that the file wasn't in the same directory as my .exe, so I went back to the app and set the properties of the file as shown below...

The main thing to note is that I changed Copy To Output Directory. With that altered I ran the app again and this time Boom, it threw an exception…

Drilling down on the exception the root cause was this…

{"Type 'Microsoft.ApplicationInsights.Extensibility.RuntimeTelemetry.RemoteDependencyModule, Microsoft.ApplicationInsights.Extensibility.RuntimeTelemetry' could not be loaded."}

The Config File

This alerted me to the content of the .config file that I'd blatantly copied and pasted from the web project, and opening it up it was evident what was happening - I'd 'told' it to load some types that didn't exist in my simple console app - or rather, the file I copied across included a bunch of types that were not referenced...

<?xml version="1.0" encoding="utf-8"?>
<?XML:NAMESPACE PREFIX = "[default] http://schemas.microsoft.com/ApplicationInsights/2013/Settings" NS = "http://schemas.microsoft.com/ApplicationInsights/2013/Settings" /><applicationinsights xmlns="http://schemas.microsoft.com/ApplicationInsights/2013/Settings">
  <!-- 
    Learn more about Application Insights configuration with ApplicationInsights.config here: 
    http://go.microsoft.com/fwlink/?LinkID=513840
    
    Note: If not present, please add <InstrumentationKey>Your Key</InstrumentationKey> to the top of this file.
  -->
  <telemetrymodules>
    <add type="Microsoft.ApplicationInsights.Extensibility.Implementation.Tracing.DiagnosticsTelemetryModule, Microsoft.ApplicationInsights"></add>
    <add type="Microsoft.ApplicationInsights.Extensibility.RuntimeTelemetry.RemoteDependencyModule, Microsoft.ApplicationInsights.Extensibility.RuntimeTelemetry"></add>
    <add type="Microsoft.ApplicationInsights.Extensibility.PerfCollector.PerformanceCollectorModule, Microsoft.ApplicationInsights.Extensibility.PerfCollector">
...

Here the TelemetryModules section is quite clearly defining a bunch of plug-ins, the first exists (as it's in Microsoft.ApplicationInsights which I have referenced), the second and third do not and sure enough the second is the subject of the exception I received. Armed with this knowledge I did a hatchet job on the .config file and removed anything I didn't have referenced from Nuget or directly. I then ran the app again and to my dismay - still nothing happened. I was expecting to see an HTTP Post request flying over the wire to Azure, but instead there was nothing.

Flush, aha, he saved every one of us!

(Sorry for the abysmal pun, I couldn’t help myself). I did a bit more digging on the TelemetryClient and found the Flush() method which I have added into the code samples above, but didn't have in my code at the time. With this added I was delighted to see a message show up inside Visual Studio that alerted me to the fact that I had managed to send an event to Azure..

I also saw this pop up in Fiddler...

So far so good. I then logged into Azure and lo and behold, I got my event!

I could even drill down and see “more” data about the event…

OK, so “more” data is somewhat subjective, but it did tell me that my event came from the UK which is correct. I have no doubt that I could augment the data being collected from my application so that the amount of detail here would be better.

Looking at what was sent to the server, it’s a simple JSON request as follows (I’ve blanked out my App Insights key, which I’m surprised to find twice in the content. If I’d designed this, the app insights key would have been a custom header, but that’s just an aside)…

And there you have it – one event in Azure, an hour or more messing around with it to understand what it’s doing, and I’ve got a load closer to working out why my web app wasn’t sending any telemetry (or rather, the custom telemetry I was expecting to send).

I hope that helps someone else! Next time I’ll see what’s up with my web app.

2 comments:

James Martin said...

This article delivers me step by step details of Console App which is good for understanding this topic. web app development US

HM Sathish said...

Good post regarding the web application development for our business. Thanks for sharing.

Web Application Development in Chennai | Android application development company