Giter Club home page Giter Club logo

perfit's Introduction

NuGet version AppVeyor

PerfIt!

Join the chat at https://gitter.im/perfIt-dotnet/Lobby

A light-weight library/framework for code/performance instrumentation in .NET (both .NET 4.52+ and .NET Core)

Core Concepts

  • Instrumentation: an aspect-oriented or closure-based wrapping of your code to measure how it performances and capture its context
  • SimpleInstrumentor: core class within PerfIt responsible for all instrumentations
  • Trace: result of an instrumentation. Contains time taken plus both configuration-based and runtime-based context
  • Tracer: A class/system that receives traces and can publish traces to storage/transports (e.g. Console, EventHub, ETW)
  • Zipkin: A distributed tracing system/framework/specification developed by Twitter
  • Zipkin Emitter: A hub where all Zipkin traces within a process is received
  • Zipkin Dispatcher: A class that receives Zipkin traces from the emitter and sends them to a transport/storage
  • EventSource: A class in .NET Framework where it raises ETW events under windows and LTTng events in Linux

Breaking changes in version 5.0.0

PerfIt 5 now supports both .NET 4.52+ and .NET Core, and it was an opportunity to get rid of some tech debt and clean up the interfaces. If you have been using previous versions of PerfIt, apart from some minor changes, your code will work as it was. But here are main changes:

  • PublishEvent property no longer exists. PerfIt always publishes EventSource events although you may remove it from the Tracers dictionary to suppress that.
  • Everything to do with Performance Counters on PerfItRuntime has moved to CounterInstaller.
  • Instead of InstrumentationContext string, now there is InstrumentationContext object where you can add a bit more context.
  • PerfitClientDelegatingHandler has moved to PerfIt.Http project/package to support both .NET 4.52+ and .NET Core
  • There is a Name property now on IInstrumentationInfo
  • There is a global static event (PerfItRuntime.InstrumentorCreated) whenever an Instrumentor is created. Ideal for modifying instrumentors that are created using attributes such as adding/removing tracers.

FAQ

What is PerfIt?

PerfIt is a light-weight and generic instrumentation lib for publishing standard instrumentation traces (Performance Counters and ETW events on Windows, LTTng traces on Linux via .NET Core's EventSource class, Zipkin traces) or your custom ones. Historically, PerfIt would only support Performance Counters and ETW, but it publish those if they are supported on the platform it runs.

What are PerfIt packages?

  • PerfIt: common constructs for instrumentation
  • PerfIt.Http: for instrumenting HttpClient
  • PerfIt.WebApi: for instrumenting ASP.NET Web API
  • PerfIt.Mvc: for instrumenting ASP.NET MVC
  • PerfIt.CoreMvc: for instrumenting ASP.NET Core MVC
  • PerfIt.Tracers.EventHub: for publishing PerfIt traces to EventHub
  • PerfIt.Zipkin: common constructs for adding Zipkin traces
  • PerfIt.Zipkin.EventHub: for publishing Zipkin traces to EventHub

Why do I need PerfIt?

If you are using .NET for a serious project, you would most likely want to instrument your code and network-bound calls. PerfIt helps to make instrumentation easier by looking after boilerplate stuff so that you focus on your business logic.

What is the overhead of using PerfIt?

It is negligible compared to the code you would normally find within an API. It should be <1ms.

What about instrumenting serving or consuming HTTP?

PerfIt has constructs for ASP.NET MVC, ASP.NET Web API, ASP.NET Core MVC and HttpClient.

What counters does it publish?

If your platform supports performance counters (Windows) and you have not disabled it, it will publish counters. There are 5 standard counters that come with PerfIt out of the box (TotalNoOfOperations, AverageTimeTaken, LastOperationExecutionTime, NumberOfOperationsPerSecond and CurrentConcurrentOperationsCount) and you can choose one or all (typically you would choose all).

You can also create your own counters by implementing a simple base class.

What is category and instance name? Is this not a left-over from Performance Counters?

Yes and no. Yes, it was added initially because of Performance Counters but still is a common sense two-level hiararchy for naming traces. So they are here to stay.

What if I just want ETW events and no Performance Counters since installing them is a hassle?

You can turn only ETW or Performance Counters or both (or None).

I am using a library which publishes counters and I have my own counters in my project and I want to turn off library counters but keep mine?

As of version 2.1, you can control counters or raising ETW by their category name in your app.config (or web.config) appSettings. The syntax for category-based configuration is to have keys as "perfit:<feature>:<categoryName>" where feature is one of "publishCounters", "publishErrors" and "publishEvent" and value is boolean. The previous global syntax of "perfit:<feature>" which turns features blanket on or off. [Bear in mind, appSettings overrides values set in code.]

Example:

<add key="perfit:publishCounters" value="true"/>
<add key="perfit:publishErrors:a" value="false"/>
<add key="perfit:samplingRate:dd" value="0.02"/>

In this case, publishCounters is globally on and publishErrors for category a is off. Also sampling rate is set to 2% for category dd.

If you need define these for an Azure application, Azure configuration schema does not allow you to use colon (:) in the name of the configuration. In this case, use pound sign (#) as the delimiter:

<add key="perfit#publishCounters" value="true"/>
<add key="perfit#publishErrors#a" value="false"/>
<add key="perfit#samplingRate#dd" value="0.02"/>

Getting Started (Measuring any part of your code)

Best way to get started is to look at the samples solution and have a look at its README.

But here are two typical scenarios, one for .NET Core (Windows/Mac/Linux) with closure-base instrumentation and other for .NET 4.52 (Windows) with aspect-oriented publishing Performance Counters

Getting Started - .NET Core (Windows/Mac/Linux)

Step 1: Create an Console project

Use Visual Studio or dotnet new to create an empty console application

Step 2: Add PerfIt to your project

Add reference to PerfIt

PM> Install-Package PerfIt

Step 3: Add this code

var si = new SimpleInstrumentor(new InstrumentationInfo()
{
    CategoryName = "test-category",
    InstanceName = "test-instance"
});

si.Tracers.Add("TextFile", new SeparatedFileTracer("trace.txt"));
si.InstrumentAsync(() => Task.Delay(100)).GetAwaiter().GetResult();
Thread.Sleep(100);
si.Dispose();
Console.WriteLine(File.ReadAllText("trace.txt"));

As you can see, traces get stored on the file. This is not an option for very high performance cases but it is OK for cases where sampling is low or the load is not too big and you can use File tailers such as Elatico's Beats/LogStash to tail this trace file.

Getting Started - ASP.NET Web API (Windows)

Step 1: Create an ASP.NET Web API

Use Visual Studio to create an ASP.NET Web API and add a controller (such as DefaultController).

Step 2: Add PerfIt to your project

In the package manager console, type:

PM> Install-Package PerfIt.WebApi

Step 3: Decorate your actions

In the actions you would want to monitor, add this attribute (we are using default counters so no need to specify them):

[PerfItFilter("MyApiCategory", Description = "My cool API"]
public string Get()
{
    ...
}

Step 4: Add an installer class

Right-click on your ASP.NET Web API and choose Add an Item and then from the menu choose "Installer Class".

Once added, click F7 to see the code and then add these lines:

public override void Install(IDictionary stateSaver)
{
 base.Install(stateSaver);
 CounterInstaller.Install(Assembly.GetExecutingAssembly(), new FilterDiscoverer());
}

public override void Uninstall(IDictionary savedState)
{
	base.Uninstall(savedState);
	CounterInstaller.Uninstall(Assembly.GetExecutingAssembly());
}

Step 5: Register your counters using InstallUtil.exe

In the command line, change directory to the .NET framework in use and then use -i switch to install ASP.NET Web API dll:

C:\Windows\Microsoft.NET\Framework64\v4.0.30319>InstallUtil -i "c:\myproject\path\bin\MyAspNetWebApi.dll"

Step 6: Use your API and see the counters being published

Your counters will be published under a category, with the same name as your project. Underneath, you will see instance(s) of your individual counters.

counters

Common scenarios

Changing default category name

You can do this by supplying your custom category name to all three methods below (make sure they are all the same):

CounterInstaller.Install("MyCategoryName");

// AND

CounterInstaller.Uninstall("MyCategoryName");

// AND

var handler = new PerfItDelegatingHandler("MyCategoryName");

Changing default instance name

By default, instance name is composed of controller name and action name. If you have two actions with the same name (overloading a method), either you need to use ActionName attribute or change the method name (e.g. instead of Get using GetCustomer).

An alternative method is to supply instance name (also useful when you want to supply your custom name):

[PerfItFilter(Description = "Gets all items",
    Counters = ...,
    InstanceName="AnyName")]
public string Get()
{
    ...
}

Turn off publishing counters

For whatever reason you might decide to turn off publishing counters. All you have to do is to add this entry to the AppSetting of your web.config:

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

As of version 2.1, there is option to turn on and off by CategoryName - see above.

Not to throw publishing errors

By default, publishing performance counters are regarded as having the same importance as the application's business logic and all publishing errors are thrown. If you would like to change this behaviour, you can do so in config:

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

If you need to turn on or off publishErrors, publishCounters or publishEvents by category, please see examples above.

FileNotFoundException when registering the DLL using InstallUtil.exe

A common problem is to encounter FileNotFoundException when registering your counters using InstallUtil. This is more common when your use Web API 2. In any case, this is a problem with InstallUtil not honouring your assembly redirects. To solve the problem (and it is just a workaround), simply copy the assembly redirect directives to InstallUtil.exe.config, run the installation and then remove them.

This has been raised a few times (see the issues, for example #11) but the problem is simply the way InstallUtil works - or rather doesn't.

What I found the best solution is to include a copy of InstallUtil.exe and its custom config (which works for your project by copying content of assemblyBinding section of the web.config) along with your deployables and have a script to install the counter, rather than relying on the standard InstallUtil on the box. These files are small and certainly a good solution.

perfit's People

Contributors

aliostad avatar aliostad-asos avatar aliozgur avatar andresdrb avatar asos-davemills avatar chrishimsworth avatar dependabot[bot] avatar eugene-g avatar folding avatar gitter-badger avatar naeemkhedarun avatar piotrtecza avatar sgarg7 avatar steelerc69 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

perfit's Issues

.NET 4.5 cannot find "System.Net.Http.Formatting, Version=4.0.0.0"

I tried installing PerfIt on .NET 4.5 project (MVC 4) and it failed with the following message:

An exception occurred during the Install phase.
System.IO.FileNotFoundException: Could not load file or assembly 'System.Net.Http.Formatting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified.

I have System.Net.Http.Formatting in the bin, but it is version 4.1.10809.0

FileLoadException

Hi,

I followed your April 1st instructions on installing and configuring this tool. I installed version 0,1.5 from nuget.

I placed the,

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

code in my WebApiConfig.Register() method

And added Installer template file (I named it PerfitInstaller), but it didn't have any Install/Uninstall virtual methods to be overwritten, only,

[RunInstaller(true)]
public partial class PerfItInstaller 
    : Installer
{
    public PerfItInstaller()
    {
        InitializeComponent();
    }
}

So the only way I deviated from your post was that I didn't implement the,

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

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

as you said... I just left everything alone in this file.

Then added,

    [PerfItFilter(Description = "Gets tenant by id",
        Counters = new[] { CounterTypes.TotalNoOfOperations, 
        CounterTypes.AverageTimeTaken })]

as an attribute on one of my Get(int id) methods.

Opened the vs command line and InstallUtil.exe -i Proto.Api.dll, it stated the commit phase completed successfully.

The log file looks like so,

Committing assembly 'D:\xxx\xxx\xxx\Proto3\Proto.Api\bin\Proto.Api.dll'.
Affected parameters are:
i =
logfile = D:\xxx\xxx\xxx\Proto3\Proto.Api\bin\Proto.Api.InstallLog
assemblypath = D:\xxx\xxx\xxx\Proto3\Proto.Api\bin\Proto.Api.dll
logtoconsole =

I do a F5, and it throws on

Application_Start => WebApiConfig.Register()

The exception is:

{"Could not load file or assembly 'System.Web.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)":"System.Web.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"}

Problem on install

After did all steps the installer show the error:

System.ArgumentException: The savedState dictionary does not contain th
d values and might have been corrupted.
An exception occurred during the Rollback phase of the installation. Th
ion will be ignored and the rollback will continue. However, the machin
ot fully revert to its initial state after the rollback is complete.

PerfItDelegatingHandler not available

Following the documentation...

"
In the WebApiConfig class when setting up the configuration, add a PerfIt delegating handler:
config.MessageHandlers.Add(new PerfItDelegatingHandler());
"

The issue is - there's no PerfItDelegatingHandler class in the solution.

Is there a working sample available? Thank you,

António

PerfItFilterAttribute - CLS Compliance

CS3016: There is CLS compliance issue on the Counters collection in the PerfItFilterAttribute.
"Arrays as attribute arguments is not CLS-compliant"

There doesn't seem to be a resolution appart from disabling the check on the whole assembly, which I do not want to do:
[assembly: CLSCompliant(false)]

Create counters for overloaded methods

As far as i have tested if we have two Get methods in our Api and add our filter attribute without specifying the name explicitly to both of the methods only one performance counter is created. I think we should consider incorperating the parameter names in case of method overloads whihc do not have implicitly named filter action. If this is not an option we can just add a documentation and notify our users to use explicit names in the action filter for overloaded methods.

InstallUtil exception on Windows Server 2008

I can run installutil on my assemby on my developer box with no problem. However, on my production server I get the following output from InstallUtil:

An exception occurred during the Install phase.
System.IO.FileNotFoundException: Could not load file or assembly 'System.Web.We
bPages, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or o
ne of its dependencies. The system cannot find the file specified.

Instances only available upon initial request

I was just wondering...what's the reason for not making all the instances declared on the action via PefItFilterAttribute available right away instead waiting for the route to be hit?

Great project by the way. (Y)

-David

Unable to user ExceptionFilterAttribute in conjunction with PerfIt

I am utilizing ExceptionFilterAttribute for exception handling in a Web API project. The ExceptionFilter hadles all of my exceptions and throws an HttpResponseException with a JSON payload in the response message.

PerfIt appears to be intercepting the HttpResponseException and throwing it's own exception instead.

The result is that I get an error page in the response and not the JSON object I sent.

Error page
perfiterror

The stack trace is pretty vague and I can't figure out where the null reference exception is thrown while debugging. PerfIt is pretty awesome, it suits my needs perfectly. Any help is appreciated.

Counters returning wrong values

I just started integrating PerfIt into my application and I am noticing that the counters don't seem to working properly.

I have installutil'd my assembly, added the PerfItDelegatingHandler, and have the following attribute on my action.

    [PerfItFilter(Description = "Get Document", Counters = new string[]
    {
        CounterTypes.TotalNoOfOperations, 
        CounterTypes.AverageTimeTaken, 
    }, Name = "GetSingle")]

If I just have the CounterTypes.TotalNoOfOperations, then the counter seems to work properly and gets incremented by 1 every time I call the action.

However if I include CounterTypes.AverageTimeTaken, as well, then the TotalNoOfOperations counter seems to increase by a random amount (3,910,611 after the first call, 11,040,734 after the second), and the AverageTimeTaken doesnt seem to get incremented at all

No unit tests!

Shameful but true. There are no unit tests in the project.

InvalidOperationException vetting Castle Windsor Interception unit tests

I am running the unit tests as a first measure baseline, and getting some errors. Perhaps along the lines that PerfIt needs to be "installed" up front?

System.InvalidOperationException was unhandled by user code
  HResult=-2146233079
  Message=The requested Performance Counter is not a custom counter, it has to be initialized as ReadOnly.
  Source=System
  StackTrace:
       at System.Diagnostics.PerformanceCounter.InitializeImpl()
       at System.Diagnostics.PerformanceCounter.Initialize()
       at System.Diagnostics.PerformanceCounter.set_RawValue(Int64 value)
       at PerfIt.Handlers.CurrentConcurrentCountHandler.<>c__DisplayClass2.<BuildCounters>b__1() in d:\Source\Spikes\PerfIt\mwpowellhtx-working\src\PerfIt\Handlers\CurrentConcurrentCountHandler.cs:line 38
       at System.Lazy`1.CreateValue()
  InnerException: 

Support for arbitrary counter handler usage inside mvc actions or web api methods

I think we can use the Disposable pattern (using) to enable arbitrary counter handler usage inside actions or web api methods. The major problem for this implementation is the discovery (install) part of the counters. But we can provide some abstract class which can be implemented just to define the counters. May be we can just use our filter attributes which will just become passive during the action/method invocation (just for counter discovery and install) and provide handy constructs for referencing inside action/webapi methods

Unhandled exception in CurrentConcurrentCountHandler

when the IIS application pool recycles, an exception is raised

Exception Details:

Instance 'xxx' already exists with a lifetime of Process. It cannot be recreated or reused until it has been removed or until the process using it has exited. already exists with a lifetime of Process.

even though I've explicitly set "RaisePublishErrors" to false

InstallUtil fails when Description is not provided

Trying to run installutil on an assembly that has a PerfItFilter where the Description is not provided throws a

An exception occurred during the Install phase.
System.ArgumentNullException: Value cannot be null.
Parameter name: help

Should probably either provide a default value, or throw a proper exception

Request/Response byte size counters

To recognise the size of incoming and outgoing messages over time, it may be useful to record the size of communications between systems. This would allow developers and operators to recognise when an API response has changed sized considerably, perhaps post-deployment or during a third party outage.

Recommendations for usage with Autofac

Hello,

I am using Autofac for my DI container. I have been learning about Autofac.Extras.DynamicProxy, which has some concerns of its own, but I wonder if you had any other recommendations for usage with Autofac?

Using DI conventions, I register my IInterceptor? Specifically, I implement a child of PerfItInterceptor, which amounts to passing a categoryName to the base class. Registering with Autofac is simple enough. However, what do I do with it in terms of registering the target(s) with the interceptor(s)?

This may be more of an AEDP question, considering the InterceptedBy extension methods want either Services, Types, or names; none of which appears to be that aligned with IInterceptor, which is my confusion at the moment.

Sorry for the breadth of the question, but wanting to connect the dots here.

Thank you!

There are no instrumentationInfos found

Hi,

I always got this exception when I try to install it. (not API 2)
System.InvalidOperationException: There are no instrumentationInfos found by the discoverer!

    `public override void Install(IDictionary stateSaver)
    {
        base.Install(stateSaver);
        PerfItRuntime.Install(Assembly.GetExecutingAssembly(), new FilterDiscoverer());
    }

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

I did what's in the readme but still cannot see the counters in the PerfMon, neither my PerFit web API project name.

Did I miss something? Because I didn't found any similar Issue in here.

Thanks in advanced.

PerfIt.Castle.Interception does not work with PerfIt version 2.2

This is what I get after upgrading to version 2.2:

Exception: System.MissingMethodException: Method not found: 'Void PerfIt.SimpleInstrumentor.Instrument(System.Action, System.String)'.
at PerfIt.Castle.Interception.PerfItInterceptor.Intercept(IInvocation invocation)
at Castle.DynamicProxy.AbstractInvocation.Proceed()

READme.rd not in sync

Could you please update README.rd file content to suit the latest API version?

Thx

Sampling should use a consistent apperoach

If we have multiple instrumentors inside the same process (and even outside), they should sample it all or none. This is a concept that also exists in zipkin.

One solution is to use correlationId's hash to sample.

Support for .NET 4.0

I know it sucks that .NET 4.0 is not there but other than async/await, .NET 4.0 does not support ETW.

What should we do @andresdrb ?

De-staticize the Runtime

My assumption is that the Runtime needs to be invoked somehow, but I am not seeing that happen in my service application. No invocations are being intercepted.

However, I noticed that the Runtime is static. That's a concern because it makes for difficult to manage Dependency Injection.

See my SO for related question.

Do I need to invoke a discoverer somewhere along the way? Also, when I am installing my service, do I also need to "install" PerfIt? Or is this more of a "soft", runtime installation, than a service installation?

Finally, when is InstallStandardCounters invoked? These are probably more than sufficient for 80% of anything I'd need, but I'd like to also decouple those via DI if possible.

Sorry if these seem like obvious questions. I just want to understand it enough through and through so that I can deploy it properly.

PerfItDelegatingHandler calls context.Handler.OnRequestStarting for all installed counters

As far as I know due to the nature of the DelegatingHandler we actually do not know the exact WebApi method being called and as a result all installed/registered counters' handlers receive the OnRequestStarting call but only one receives OnRequestEnding call when async send completes. Is it possible that we find a way to identify which WebApi Controller methods is being processed if not shall we consider implementing interception in filter level (like in PerfItMvc ) but not in DelegatingHandler level.

Support for MVC actions

I think we can generalize some parts of our code base so that we can support MVC actions as well as Web API methods. We can start by making the following changes

  • Change the PerfItRuntime.Install method
  • Add an mvc filter attribute
  • Remove or modify PerfItContext class

I already have a stable and working implementation (PerfItMvc) for MVC actions forked from PerfIt so that shall not be a complicated task

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.