(Print this page)

Instrumenting Windows application using Application Insights
Published date: Sunday, January 28, 2018
On: Moer & Éric Moreau's web site

Instrumenting applications have always been something useful for developers to find out which parts of their applications (and those that are not). But too often, that kind of feature that does not really bring tangible benefits to users is left aside and never implemented.

Microsoft has made available a very simple mechanism that will let you start instrumenting your application. This mechanism is available to any application running on a computer connected to the Internet. It is not reserved to Web applications.

All you need is an application and an Azure account.

The downloadable code

This month’s downloadable demo solution contains both VB and C#. The solution was created using Visual Studio 2017.

Creating the Application Insights resource

Before writing code, we will need to create the Application Insights resource on the Microsoft Azure portal.

After you logged in to your Azure account, click on the New link from the menu on the left, select Developer tools and then Application Insights. This will show you a panel letting you enter the name of your application, the name of your Resource Group (as well as some other habitual Azure settings). Click the Create button to create the resource.

Figure 1: Creating the Application Insights resource

After a few seconds, a message should tell you that your new resource has been created and is ready to be used. We will need to find the “Instrumentation Key” of the newly created resource because we will need to provide that value to our application to link the application and the Azure resource.

You can find this key by clicking on the All resources link from the menu on the left, find and select your Application Insights resource from the list of resources and ensure that Overview is selected. On the panel on the right, you should see the “Instrumentation Key”.

Figure 2: Getting the Instrumentation Key

Creating the project

Now that we have the resource created in Azure, it is time to start writing some code.

Open Visual Studio and create a new project for any application type.

We then need to add a NuGet package to our project. From the solution explorer, right-click on your project and select “Manage NuGet packages…”. Browse the list to find Microsoft.ApplicationInsights.WindowsServer and click the install button.

Figure 3: Adding the NuGet package

Creating the test UI

I have created a Windows Forms project. I will then create a Windows Forms. But be advised that the code that will be provided next would work in any application (console, WPF, …).

My form is very simple. It contains 3 buttons; each button will log some instrumentation. I also created a second form (Form2) which has nothing more than a button to close it.

Figure 4: The demo UI

Writing instrumentation code

With the references and the test UI in place, we are ready to write up some code. Don’t expect to see tons of code here!

The first thing is to wire up this application with the resources we have created in Azure. Have a look at this first snippet of code:

Private mTC As New TelemetryClient()

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    ' Link to the Application Insights resource
    mTC.InstrumentationKey = "YourInstrumentationKeyGoesHere"

    ' Set session data
    mTC.Context.User.Id = Environment.UserName
    mTC.Context.Session.Id = Guid.NewGuid().ToString()
    mTC.Context.Device.OperatingSystem = Environment.OSVersion.ToString()

    ' Log a page view
    mTC.TrackPageView("Form1_Load")
End Sub

Protected Overrides Sub OnClosing(e As CancelEventArgs)
    If mTC IsNot Nothing Then
        mTC.Flush() ' only for desktop apps

        ' Allow time for flushing
        Threading.Thread.Sleep(1000)
    End If
    MyBase.OnClosing(e)
End Sub
private TelemetryClient mTC = new TelemetryClient();

private void Form1_Load(object sender, EventArgs e)
{
    // Link to the Application Insights resource
    mTC.InstrumentationKey = "YourInstrumentationKeyGoesHere";

    // Set session data:
    mTC.Context.User.Id = Environment.UserName;
    mTC.Context.Session.Id = Guid.NewGuid().ToString();
    mTC.Context.Device.OperatingSystem = Environment.OSVersion.ToString();

    // Log a page view:
    mTC.TrackPageView("Form1_Load");
}

protected override void OnClosing(CancelEventArgs e)
{
    if (mTC != null)
    {
        mTC.Flush(); // only for desktop apps

        // Allow time for flushing:
        System.Threading.Thread.Sleep(1000);
    }
    base.OnClosing(e);
}

In this portion of code, you can see that an instance of the TelemetryClient is declared at the class level to be available everywhere in that class. The form’s load event then initializes that instance by providing the instrumentation key you obtained from the Azure portal before (see figure 2). You should also initialize some other properties like the user, the session, and the device to get some information on the context your instrumentation is done. Finally, the form’s load calls the TrackPageView to send information to Azure.

You can also see that when the form’s is closing, the instance of the TelemetryClient is flushed to ensure that the stream is correctly closed and that all instrumentation information is getting sent to Azure.

The test form also has 3 buttons. Some code is attached to these buttons:

Private Sub button1_Click(sender As Object, e As EventArgs) Handles button1.Click
    'Log a button click
    mTC.TrackEvent("Button1 click")
    Dim f = New Form2(mTC)
    f.Show()
End Sub

Private Sub button2_Click(sender As Object, e As EventArgs) Handles button2.Click
    'Log an event
    Dim Timer = Stopwatch.StartNew()

    Try
        'do something useful here
        Threading.Thread.Sleep(2000)
    Finally
        mTC.TrackEvent("Button2 click",
                New Dictionary(Of String, String) From {{"Fake property", DirectCast(sender, Button).Name}},
                New Dictionary(Of String, Double) From {{"duration", Timer.ElapsedMilliseconds}})
    End Try
End Sub

Private Sub button3_Click(sender As Object, e As EventArgs) Handles button3.Click
    'Log an exception
    mTC.TrackException(New InvalidOperationException("Your message goes here"))
End Sub
private void button1_Click(object sender, EventArgs e)
{
    //Log a button click
    mTC.TrackEvent("Button1 click");
    Form2 f = new Form2(mTC);
    f.Show();
}

private void button2_Click(object sender, EventArgs e)
{
    //Log an event
    var timer = Stopwatch.StartNew();

    try
    {
        //do something useful here
        System.Threading.Thread.Sleep(2000);
    }
    finally
    {
        mTC.TrackEvent("Button2 click",
            new Dictionary() { { "Fake property", ((Button)sender).Name } },
            new Dictionary() { { "duration", timer.ElapsedMilliseconds } });
    }
}

private void button3_Click(object sender, EventArgs e)
{
    //Log an exception
    mTC.TrackException(new InvalidOperationException("Your message goes here"));
}

The code of button1 simply calls TrackEvent to add data to the telemetry that we will see later. Also, an instance of Form2 is created and shown (notice that we pass the instance of the TelemetryClient to avoid recreating it on the second form). This second form only use the TrackPageView method to simulate another page/form being displayed.

Button2 shows another of calling the TrackEvent method with some more interesting data. This time we send some properties and some metrics that can help you monitor/debug your application (result shown in figure 5). And since you are passing dictionaries, you can pass multiple value all at the same time.

Button3 simply shows that you can call the TrackException method (result shown in figures 6 and 7).

Running the demo app

That’s all you need to start instrumenting your application. Initialize an instance of the TelemetryClient and use one of the Track* methods (and there are more than TrackPageView, TrackEvent, TrackException depending on what you need to monitor).

Run the demo application and click on each button one after the other. Finally close the application. If all went well, your telemetry information should be sent to your Azure resource.

Viewing that instrumentation results

We have now logged information but have not seen anything yet.

After a minute or 2 (yes that service is not really a live feed), you will be able to see your results in the Azure portal. If you need a 1-second latency feed, have a look at https://docs.microsoft.com/en-us/azure/application-insights/app-insights-live-stream.

Return to your Azure portal, and open your Application Insights resource you have created. On the panel that will open, click the Search button (top left of the panel).

As shown in figure 5, the Search panel will open and if you have waited long enough, you will see a chart representing your instrumented session. Below the chart, you see the results of each call to the various Track* methods.

For example, figure 5 shows the result of the call to TrackEvent done by button2, the one that includes properties and metrics. You can see in the right panel that this particular data is found under the “Custom Data” section.

Figure 5: The result of a TrackEvent call

Different methods render different results. Figure 6 shows the result of a TrackException call.

Figure 6: The result of a TrackException call

One nice feature found in the exception panel is the timeline (for the current session or the user). For example, figure 7 shows a session timeline which might help you figure how a user got to the exception.

Figure 7: Viewing a session timeline

Conclusion

The learning curve is not really on how to use the TelemetryClient object, it is much more on how to use the Azure portal to get the real benefits from this object.

You should really have a look at Navigation and Dashboards in the Application Insights portal) and at Using Search in Application Insights to get a good understanding of viewing your result.


(Print this page)