Vaughan Reid's blog

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

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));
			notSteveCreatedCounter.WriteMetric(Interlocked.Increment(ref notSteveCreatedCount));

I then register it as a singleton in startup ConfigureServices.

public void ConfigureServices(IServiceCollection services)


	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));
		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.