Vaughan

Measuring .Net Core: 3. dotnet-counters with a custom provider

.NET Core, Dotnet Tools, Measuring

This is the third in a series of posts covering measuring a .Net Core application. If you want to try follow the code then you can have a look at this repo: Blog-Diagnostics.

This is the plan for the series. I will update this with links as it evolves.

  1. Setting up local diagnostics tools
  2. Using dotnet-counters
  3. dotnet-counters with a custom provider
  4. Using dotnet-gcdump to investigate memory leaks
  5. Creating a dump file when a ASP.NET Core application crashes

Now that we have tried using the built in providers for the dotnet-counters tool, lets try create our own custom one.

You can achieve this by using a custom EventSource. You just need to create a class that implements EventSource and populate different types of counters depending on what you are trying to achieve.

The event source that I created will report as Diagnostics.Person and does a silly measure of the amount of gets of people with steve in their name. Way too many steves around 😉


[EventSource(Name = PersonEventSource.SourceName)]
public class PersonEventSource : EventSource
{
    readonly EventCounter steveCreatedCounter;

    int steveCreatedCount = 0;

    readonly EventCounter notSteveCreatedCounter;

    int notSteveCreatedCount = 0;

    public PersonEventSource()
    {
        steveCreatedCounter = new EventCounter("Steve created", this);
        notSteveCreatedCounter = new EventCounter("Not Steve created", this);
    }

    const string SourceName = "Diagnostics.Person";
    [Event(1, Level= EventLevel.Informational)]
    public void Created(string name)
    {
        if (name.Contains("Steve", StringComparison.InvariantCultureIgnoreCase))
        {
            steveCreatedCounter.WriteMetric(Interlocked.Increment(ref steveCreatedCount));
        }
        else
        {
            notSteveCreatedCounter.WriteMetric(Interlocked.Increment(ref notSteveCreatedCount));
        }
    }
}

I then register it as a singleton in startup ConfigureServices.


public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();

    services.AddSingleton<PersonEventSource>();

    services.AddScoped<IPersonService, PersonService>();
}

Then injected it into my service.


public class PersonService : IPersonService
{
    private readonly PersonEventSource personEventSource;

    public PersonService(PersonEventSource personEventSource)
    {
        this.personEventSource = personEventSource;
    }
    public async Task<Person> GetAsync(string name)
    {
        await Task.Delay(TimeSpan.FromSeconds(1));
        personEventSource.Created(name);
        return new Person { Name = name, Age = 18 };
    }
}

After restarting the application I can run the counters command as:

dotnet counters monitor -p 24 --providers Diagnostics.Person

This will give the following result after a little prodding.

Obviously not a real example but hopefully you can see the power. An example I could use at work is for an application processing realtime trades. I could add metrics on the average process time per asset class.

Related Posts

BMC logoBuy me a coffee