Monday, 1 April 2013

Monitor your ASP.NET Web API application using your own custom counters

[Level T2] OK, so you have created your Web API project and deployed into production and now boss says dude, we have performance problems. Or maybe head of testing wants to benchmark the application and monitor it over the course of next releases so we catch problems early. Or you are just a responsible geek interested in the performance of your code.

NOTE: THIS BLOG POST REFERS TO AN EARLIER VERSION OF PERFIT. PLEASE VISIT https://github.com/aliostad/PerfIt FOR UP-TO-DATE DOCUMENTATION

In any case, no serious web code can be written without having performance in mind. Problem is that existing system, .NET and ASP.NET performance counters can go as far as telling you overall picture of the performance and the metrics usually coalesced into a single value while you need to drill down to individual APIs and see what's happening. Now this can be another burden on your already squeezed time remaining. So how easy is it to publish counters for your individual API? Just these few steps! TLDR; :

  1. Use NuGet to install PerfIt! into your ASP.NET Web API project (make sure you get version +0.1.2 - there was a bug fixed in this version)
  2. Add PerfitDelegatingHandler to the list of your MessageHandlers
  3. Decorate those actions you want to monitor
  4. Use "Add New Item" to add an Installer class into your Web API project. Write just a single line of code for Install and Uninstall.
  5. Use InstallUtil.exe in an administrative command window to install (or uninstall) your counters. Done! 

Seeing performance counters of your own project is kinda cool!

1-Adding PerfIt! to your project

So to add PerfIt! to the project, simply use NuGet console:
PM> Install-Package PerfIt


2-Adding PerfItDelegatingHandler 

Now we need to add the delegating handler:

config.MessageHandlers.Add(new 
      PerfItDelegatingHandler(config, "My test app"));

The string passed in here is the application name. This will be used as the instance name in the performance counter. You can see that in the screenshot above.

3-Decorate actions

For any action that you want the counters to be published, use PerfIt action filter and define the counters you want to see published:

// GET api/values
[PerfItFilter(Description = "Gets all items",
   Counters = new []{CounterTypes.TotalNoOfOperations,
   CounterTypes.AverageTimeTaken})]
public IEnumerable<string> GetAll()
{
    Thread.Sleep(_random.Next(50,300));
    return new string[] { "value1", "value2" };
}

// GET api/values/5
[PerfItFilter(Description = "Gets item by id", 
   Counters = new[] { CounterTypes.TotalNoOfOperations, 
   CounterTypes.AverageTimeTaken })]
public string Get(int id)
{
    Thread.Sleep(_random.Next(50, 300));
    return "value";
}

Here we have decorated GetAll and Get to publish two types of counters (currently these counters are available but more will be added - see below).

The format of the counter will be [controller].[action].[counterType] (see screenshot above). As such, please note that we had to change the first Get to GetAll to so that the counter names do not get mixed up. If you cannot do that (while ASP.NET Web API allows you do change the name as long as the action starts with the verb), alternatively use the Name property of the filter to define your own custom name (which we did not specify here to allow default naming take place).

Description property will appear in the perfmon.exe window and is known as CounterHelp. Counters is an array of string, each string being a defined against PerfIt! runtime (see roadmap for more info) as a counter type. Another option is the ability to define Category for the counter which we also did not specify so by default, it will be the assembly name. You can see the category in the screenshot above as PerfCounterWeb (see the typo!).

4-Adding Installer to your project 

Now use "Add New Item" to add an installer class to your project. You might have not seen this in the new item templates but it is definitely there (screenshot from VS2012 but project is .NET 4.0 so can be done in VS2010):


After adding the class, override Install and Uninstall methods and add the code below (hit F7 to see the code):

public override void Install(IDictionary stateSaver)
{
    base.Install(stateSaver);
    PerfItRuntime.Install();
}

public override void Uninstall(IDictionary savedState)
{
    base.Uninstall(savedState);
    PerfItRuntime.Uninstall();
}

5-Use installutil.exe to install counters

Just make sure you open an administrative command window. Use Visual Studio command prompt since it has the right path for InstallUtil.exe. cd to your bin folder and register your assembly:
c:\projects\myproject\bin>InstallUtil.exe -i MyWebApplication.dll
This should do the trick. Use -u switch to uninstall the counters.

That is all that is needed. Just hit your app and start benchmarking your app in the perfmon.exe.

Turning off the publishing of counters

In normal/production circumstances, you might wanna turn off publishing of the performance counters. In this case, you can put the line below in the appSettings of your web.config:

<appSettings>
    <add key="perfit:publishCounters" value="false"/>

I have kept the default behaviour to publish counters - so to eliminate one configuration step to get up and running. This may change in the future - but unlikely.

PerfIt! Roadmap

I needed to add performance counters to my Web API application. With wife away and a few Easter bank holiday days, I managed to start and finish version 0.1 of PerfIt! library.

Future work includes adding more counter types and looking at improving the pipeline. PerfIt! has been built on the top of its own extensibility framework so very easy to add your own counters, all you need is to implement CounterHandlerBase and then register the handler in PerfItRuntime.HandlerFactories.

Any problems, issues, comments or feedbacks, please use the GitHub issues to get it touch. Enjoy!

2 comments:

  1. If you want to track how many times a certain action is called and how long it takes to run, I would highly recommend using an application performance management (APM) solution that would do that automatically and much more. Check out Stackify's application performance management

    ReplyDelete
  2. Can we add custom counters? I want to know time taken by each request instead of average. Is this possible?

    ReplyDelete