APM tips blog

Blog about application monitoring.

JavaScript Snippet and Instrumentation Key

| Comments

When you create a new web application in Visual Studio 2013 you can chose to enable Application Insights for it. Once enabled - JavaScript snippet will be inserted into page template document \Views\Shared\\_Layout.cshtml:

This JavaScript snippet will collect end user behavior information in portal. You may notice that Instrumentation Key is set to constant in this snippet:

1
instrumentationKey:"dbdf606c-48ec-4beb-b82d-2a9e7a90e5a4"

Constant works fine unless you want to change the key before deploying to production. Here is how you can change default snippet in \Views\Shared\\_Layout.cshtml to use the same instrumentation key as server monitoring using:

1
instrumentationKey:"@Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration.Active.InstrumentationKey"

There are reasons not to use this by default. Performance is one of them. You may also want to separate end user behavior data from server-side telemetry. In any case keep in mind - by default there are two places where you need to change your instrumentation key when you deploying your application to production.

Programmatically Set Instrumentation Key

| Comments

As telemetry became a part of engineering process I hear one question more and more often - how can I separate events reported during development from data collected from production deployment? How can I limit access to data and integrate telemetry into my continues integration infrastructure? How can I separate events from staging and production, from different versions of application, from different components inside the application?

Well, nobody knows the answer better then you. Application Telemetry SDK is flexible and gives you full controls over data and configure data collection the way you need it. There are couple ways to slice your data. In this article I’ll explain how to separate telemetry data by sending it to different components.

Every component in Application Insights is represented by a single Instrumentation Key. You can get it in “properties” section of your component:

Easiest way to configure instrumentation key is to set it in ApplicationInsights.config. Whenever Application Insights will need to send data for the first time it will attempt to read instrumentation key from this config file. You can use TransformXml msbuild task to automate the release pipeline. Here is config snippet you need to modify:

1
<InstrumentationKey>ec126cb1-9adc-4681-9cd4-0fcad33511c9</InstrumentationKey>

However this approach is not working well with some deployments. You may already have distributed configuration management system in place. One example may be Azure Cloud Services where you may prefer to store instrumentation key in cscfg file. In this case you can leave InstrumentationKey section of ApplicationInsights.config file blank and set it programmatically:

1
2
3
TelemetryConfiguration.Active.InstrumentationKey = "ec126cb1-9adc-4681-9cd4-0fcad33511c9";
TelemetryClient tc = new TelemetryClient();
tc.TrackTrace("This trace goes to the default source");

The best place to do it for web application is Global.asax before any telemetry data items were tracked. Note, that if you’ll attempt to send telemetry data item before instrumentation key was set TelemetryClient.Track[Foo] method will throw an exception.

In both cases - using config or setting key programmatically you’ll see data reported into the same component. This key will be used as default for all telemetry clients you’ll instantiate.

There are situations when one default key is not enough. Scenarios I can imagine are:

  • reporting data from payment processing library separately from other telemetry
  • split telemetry information by tenants of your application and grant them access to their data only
  • library developer wants to collect telemetry from his library, not send it to application that uses this library

For all this scenarios you’ll need to configure your own custom telemetry client and set it’s instrumentation key:

1
2
3
TelemetryClient tcCustom = new TelemetryClient();
tcCustom.Context.InstrumentationKey = "67989f95-d6a2-46a9-918b-028a6a2070c1";
tcCustom.TrackTrace("This trace goes to custom telemetry client");

Sometimes you might want even more fine grained control over data. You may want to decide where to send telemetry data item based on it’s properties. For instance, you can have a library that decides where to send telemetry item based on current thread identity. In this case you’ll create and populate telemetry item and then pass it to this library so it will set the correct Instrumentation Key on this item:

1
2
3
4
TelemetryClient tcDefault = new TelemetryClient();
TraceTelemetry trace = new TraceTelemetry("This trace goes to the custom source");
trace.Context.InstrumentationKey = "67989f95-d6a2-46a9-918b-028a6a2070c1";
tcDefault.TrackTrace(trace);

Both code examples will send trace message to your custom application even though configuration file defines another instrumentation key.

Summary

Application Insights SDK gives you a flexible way to configure data collection. You have full programmatic control over where data will be reported to and it is very easy to integrate Application Insights into any continues deployment process with the minimal coding.

Collect ASP.NET MVC Web API Traces With Application Insights

| Comments

Application Insights is designed to be a continuation of development expirience. As you use traces for development it is very easy to start collecting traces for your application in production. Today I’ll walk thru steps to enable traces collection using Application Insights.

I’m going to demo how to enable System.Diagnotsics traces. One may argue that those traces are not very efficient and will be absolutely correct. There are many tracing libraries that are faster and more powerful. However there are lots of libraries out wild which already instrumented with this tracing framework. One of example is Web API tracing library.

Traced from ASP.NET Web API

Let’s take a simple Web API application. I created one using File->New dialog in VS 2013. Following the steps in this article we will enable tracing by installing package

1
PM> Install-Package Microsoft.AspNet.WebApi.Tracing 

and then modifying WebApiConfig.cs by adding call to extension method defined in that nuget package:

1
config.EnableSystemDiagnosticsTracing();

You may already have Application Insights enabled for your application. If not just follow instructions. Now you are ready to enable traces collection from your application. Enabling tracing is very easy. Just install the nuget:

1
PM> Install-Package Microsoft.ApplicationInsights.TraceListener -Pre

Under the hood nuget will add reference to new assembly containing trace listener and add this trace listener into web.config:

1
2
3
4
5
6
7
<system.diagnostics>
<trace autoflush="true" indentsize="0">
  <listeners>
    <add name="myAppInsightsListener" type="Microsoft.ApplicationInsights.TraceListener.ApplicationInsightsTraceListener, Microsoft.ApplicationInsights.TraceListener" />
  </listeners>
</trace>
</system.diagnostics>

Now when you running Web API methods you will not only see those methods as requests, but also traces associated with these requests. On my machine I just run application under debugger and called this GET method “http://localhost:57444/api/values” from browser. Here are result I see in azure portal: You see step by step execution of Web API pipeline - in the portal traces are in reverse order:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Request, Method=GET, Url=http://localhost:57444/api/values, Message='http://localhost:57444/api/values'
Message='Values', Operation=DefaultHttpControllerSelector.SelectController
Message='WebApplication1.Controllers.ValuesController', Operation=DefaultHttpControllerActivator.Create
Message='WebApplication1.Controllers.ValuesController', Operation=HttpControllerDescriptor.CreateController
Message='Selected action 'Get()'', Operation=ApiControllerActionSelector.SelectAction
Message='The authentication filter did not encounter an error or set a principal.', Operation=HostAuthenticationFilter.AuthenticateAsync
Message='Will use same 'JsonMediaTypeFormatter' formatter', Operation=JsonMediaTypeFormatter.GetPerRequestFormatterInstance
Operation=HostAuthenticationFilter.ChallengeAsync
Message='Selected formatter='JsonMediaTypeFormatter', content-type='application/json; charset=utf-8'', Operation=DefaultContentNegotiator.Negotiate
Operation=AuthorizeAttribute.OnAuthorizationAsync, Status=401 (Unauthorized)
Operation=ValuesController.ExecuteAsync, Status=401 (Unauthorized)
Operation=PassiveAuthenticationMessageHandler.SendAsync, Status=401 (Unauthorized)
Response, Status=401 (Unauthorized), Method=GET, Url=http://localhost:57444/api/values, Message='Content-type='application/json; charset=utf-8', content-length=unknown'
Operation=JsonMediaTypeFormatter.WriteToStreamAsync
Operation=ValuesController.Dispose

This it pretty cool, all existing traces will be sent to Application insights, indexed and sliced by requests and sessions. For every request you will see all troubleshooting informaiton. No more remote desktop to production server to get traces from the local file!

Named trace providers

Once installed Application Insights listen for default trace source. However your trace source may be named. In this case you’ll need to adjust configuration. Here is how to enable Application Insights tracing to listen for System.Net trace source (and shoot yourself in the foot ;-)). I haven’t planned that shooting part of this example. Let me explain what I did.

First, I moved Application Insights trace listener to sharedListeners section and added System.Net trace source. Here is how web.config looks like after my change:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<system.diagnostics>
<trace autoflush="true" indentsize="0">
  <listeners>
    <add name="myAppInsightsListener" />
  </listeners>
</trace>
<sources>
  <source name="System.Net" switchName="sourceSwitch" tracemode="includehex" maxdatasize="1024">
    <listeners>
      <add name="myAppInsightsListener" />
      <remove name="Default"/>
    </listeners>
  </source>
</sources>
<switches>
  <add name="sourceSwitch" value="Information"/>
</switches>
<sharedListeners>
  <add name="myAppInsightsListener" type="Microsoft.ApplicationInsights.TraceListener.ApplicationInsightsTraceListener, Microsoft.ApplicationInsights.TraceListener" />
</sharedListeners>
</system.diagnostics>

Then I modified my applciaiton to make a simple call to bing:

1
2
3
4
5
var request = (HttpWebRequest)WebRequest.Create(new Uri("http://bing.com"));
using (var stream = new StreamReader(request.GetResponse().GetResponseStream()))
{
    stream.ReadToEnd();
}

And finally I started my application and… wait for it… got throttled on Application Insights endpoint. You can see 5 requests and 1.2K traces:

I looked at couple traces and quickly realized that I fall into recursion. First request to application was collected and generated Application Insights data item. This data item was compressed and sent to Application Insights using http call. This http call produced tons of traces (System.Net is quite chatty trace source). Those traces in turn were grouped into bunch, compressed and… sent using http that produced more http traces. In fact I was throttled even before a call to bing.com was traced ;-). Here is a trace message that helped me figure this out:

1
[1520] HttpWebRequest#65064868 - Request: POST /v2/track HTTP/1.1

One of the reasons why it happened is that in Visual Studio Application Insights works in “developer mode” that ensure data items are sent to portal really quick so you can see your telemetry data almost instantaneously.

Summary

It is very easy to collect traces using Application Insights. However it is important to be cautious of tracing level you configured.