Joydip Kanjilal
Contributor

How to use EventCounters in .NET Core

how-to
Jun 22, 20236 mins

Take advantage of EventCounters in .NET Core to gain insights into your application’s performance in real time.

1 measure roi
Credit: Thinkstock

When working in .NET or .NET Core applications, you will often want to profile the performance of your application to be aware of any potential bottlenecks before you deploy the application to the production environment. EventCounters provides a collection of performance metrics you can use for this.

This article discusses how we can work with EventCounters in .NET Core, providing code examples to help you get started. To work with the code examples provided in this article, you should have Visual Studio 2022 installed in your system. If you don’t already have a copy, you can download Visual Studio 2022 here.

Create a console application project in Visual Studio

First off, let’s create a .NET Core console application project in Visual Studio. Assuming Visual Studio 2022 is installed in your system, follow the steps outlined below to create a new .NET Core console application project in Visual Studio.

  1. Launch the Visual Studio IDE.
  2. Click on “Create new project.”
  3. In the “Create new project” window, select “Console App (.NET Core)” from the list of templates displayed.
  4. Click Next.
  5. In the “Configure your new project” window, specify the name and location for the new project.
  6. Click Next.
  7. In the “Additional information” window shown next, choose “.NET 7.0 (Standard Term Support)” as the Framework version you would like to use.
  8. Click Create.

We’ll use this .NET 7 console application project to work with EventCounters in the subsequent sections of this article.

What are EventCounters?

EventCounters are the cross-platform, lightweight, .NET Core counterpart to the performance counters of the .NET Framework for Windows. They are APIs for collecting lightweight performance data in real time in your .NET Core applications.

An EventCounter is a feature of EventSource that is designed for capturing a specific low-level performance metric. Different EventCounters track CPU usage, memory consumption, the number of threads, and many other aspects of .NET Core and ASP.NET Core runtime performance.

To use EventCounters in .NET Core, you must first create a class that extends the System.Diagnostics.Tracing.EventSource class. Then you can implement any EventCounters that provide the performance metrics you wish to track. You can observe the performance counter data published by EventCounters using any number of performance monitoring tools. We’ll use the handy dotnet-counters tool here.

Install dotnet-counters

To get started using the dotnet-counters tool, you must first install it using the following command at the console window.

dotnet tool install --global dotnet-counters
eventcounters 01 IDG

Figure 1. Installing dotnet-counters.

Once dotnet-counters is installed, press F5 to run the console application we created above. Figure 2 below shows the console application in execution.

eventcounters 02 IDG

Figure 2. Executing our default .NET Core console application.

The dotnet-counters tool allows you to investigate performance counters in your .NET Core applications. To display a list of processes that can be monitored, just run the following command at the command window.

dotnet-counters ps

Figure 3 shows the list of processes running.

eventcounters 03 rev IDG
Figure 3. Viewing the list of running processes in dotnet-counters.

Once the console application has started, execute the following command at the command window to monitor the console application.

dotnet-counters monitor -n EventCountersDemo
eventcounters 04 IDG

Figure 4. Monitoring our console application in dotnet-counters.

Implement EventCounters in .NET Core

To publish your own performance counters in .NET Core, you should implement an EventSource class. The reason is that EventCounters are developed on top of .NET Core’s tracing mechanism.

Create a class named CustomEventSource in a file of the same name with a .cs extension. Because all EventCounters must be registered against an EventSource, your CustomEventSource class should extend the System.Diagnostics.Tracing.EventSource class.

Replace the default generated code of the file you just created with the source code given in the listing given below.

    [EventSource(Name = "EventCountersDemo.CustomEventSource")]
    public sealed class CustomEventSource : EventSource
    {
        public static readonly CustomEventSource Instance = new();
        private readonly IncrementingEventCounter _incrementingEventCounter;
        private bool _disposedValue;
        private CustomEventSource()
        {
            _incrementingEventCounter = new
            IncrementingEventCounter("MyCustomCounter", this)
            {
                DisplayName = "Incrementing Counter"
            };
        }
        public void IncreaseCounterValue()
        {
            _incrementingEventCounter.Increment();
        }
        public void Dispose() => Dispose(true);
        protected override void Dispose(bool disposing)
        {
            if (!_disposedValue)
            {
                if (disposing)
                {
                    _incrementingEventCounter?.Dispose();
                }
                _disposedValue = true;
            }
            base.Dispose(disposing);
        }
    }

We will trigger the event counting using a bit of custom code. To do this, replace the default generated code of the Program.cs file with the following code.

using EventCountersDemo;
Task.Run(async () => await CounterIncrementor());
Console.ReadKey();
async Task CounterIncrementor()
{
    while (true)
    {
        CustomEventSource.Instance.IncreaseCounterValue();
        await Task.Delay(500);
    }
}

To monitor the console application now, run the following command at the command window:

dotnet-counters monitor -n EventCountersDemo --counters EventCountersDemo.CustomEventSource

The –counters parameter enables us to specify the particular event source we are interested in monitoring. In this example, the event source name is EventCountersDemo.CustomEventSource.

Figure 5 shows the output on execution of the preceeding command.

eventcounters 05 IDG

Figure 5. Monitoring our CustomEventSource in dotnet-counters.

Consume EventCounters in .NET Core

EventCounters can be consumed using EventLKisteners and EventPipes. You can consume EventCounters in two different ways, in-proc and out-of-proc. You can consume a counter in an in-proc way using the EventListener API. To consume a counter in an out-of-proc way you should use an EventPipe.

The following code listing illustrates how you can consume EventCounters in an in-proc way using the EventListener class.

   public sealed class CustomEventCounterListener : EventListener
   {
       protected override void OnEventSourceCreated(EventSource eventSource)
       {
           if (eventSource.Name == "EventCountersDemo.CustomEventSource")
           {
               var args = new Dictionary<string, string?> { ["EventCounterIntervalSec"] = "1" };
               EnableEvents(eventSource, EventLevel.Verbose, EventKeywords.All, args);
           }
       }
       protected override void OnEventWritten(EventWrittenEventArgs eventWrittenEventArgs)
       {
           if (!eventWrittenEventArgs.EventName.Equals("EventCounters"))
           {
               return;
           }
           if (eventWrittenEventArgs.Payload.First() is not IDictionary<string, object> payload)
           {
               return;
           }
           for (int i = 0; i < eventWrittenEventArgs.Payload.Count; ++i)
           {
               if (eventWrittenEventArgs.Payload[i] is IDictionary<string, object> eventPayload)
               {
                   Console.WriteLine($"{payload["DisplayName"]} - {payload["Increment"]}");
               }
           }
       }
   }

EventSources are typically used for diagnosing, logging, and tracking application behavior. An EventCounter, on the other hand, is better suited for performance profiling, optimization, and diagnostic purposes. The primary use of EventCounters is as a diagnostic or profiling tool, not as a tool for monitoring health and performance in production. To monitor applications deployed in production, you should use higher-level monitoring and logging systems.

Joydip Kanjilal

Joydip Kanjilal is a Microsoft Most Valuable Professional (MVP) in ASP.NET, as well as a speaker and the author of several books and articles. He received the prestigious MVP award for 2007, 2008, 2009, 2010, 2011, and 2012.

He has more than 20 years of experience in IT, with more than 16 years in Microsoft .Net and related technologies. He has been selected as MSDN Featured Developer of the Fortnight (MSDN) and as Community Credit Winner several times.

He is the author of eight books and more than 500 articles. Many of his articles have been featured at Microsoft’s Official Site on ASP.Net.

He was a speaker at the Spark IT 2010 event and at the Dr. Dobb’s Conference 2014 in Bangalore. He has also worked as a judge for the Jolt Awards at Dr. Dobb's Journal. He is a regular speaker at the SSWUG Virtual Conference, which is held twice each year.

More from this author