Monitoring your applications using custom performance counters
#Here is an old blog, though with a quite useful insight
If you are like me, you have learned not always to rely on hardware to run your perfectly written applications. Sometimes, and without any reasons, applications just refused to start. It happened to me, a workstation that was supposed to be running 24/7 was shutdown by a new employee who did not read the yellow Post-it stuck on the screen. The impact was not dramatic but I have looked around to find a way to monitor my physically distributed applications.
I didn’t want to rely on a database to store trace. I wanted something else. I finally found, what I think is ideal for this situation:The Performance Counters. That let me monitored a computer using another computer (I hope the 2 won’t go down at the same time).
What they are
Windows performance counters allow your applications to publish, capture, and analyze the performance data that are provided by others applications. You can use this information to determine bottlenecks, performance, and/or reliability.
For example, you might use a performance counter to track the messages queued in a stack of your own and write code that performs a specific action whenever the queue reaches a preset limit.
Visual Studio .NET provides everything we need to easily connect to performance counters on both local and remote computers and retrieve values from these counters. We can also create our very own custom counters.
How to use them
We have to create our very own Category that will contain our Counters. All those need to be created at the same time. Also, if theCategory already exists, it cannot be created again.
Once created, Counters can be used in operations that will let us increment its value, decrease its value, or read the current value.
Create the demo solution
A simple application would have done the 3 operations I wanted to show you. But I found this to simplistic.
To have a more realistic solution, we will create 3 projects. The first project will increment counters. The second one will decrease these same counters. And guess what, the last one will read the current values and display them.
The first application: Incrementing counters
This first application is the more complex and has more lines then the 2 others. It only counts about 30 lines of codes! Its interface is very simple. It has 2 buttons. Each button increments a different counter. What you don’t see is that these counters are also created here.
Figure 1: The first application
The first thing you will find at the top of each application is 3 constants declared so that we don’t do any typo mistakes:
'Declare constants because we want theses 'same values through all applications Private Const kCategoryName As String = "EMoreau-DemoApp" Private Const kCounter1Name As String = "Counter1" Private Const kCounter2Name As String = "Counter2"
Then if you look at the Form_Load event procedure, you will find this code:
If Not PerformanceCounterCategory.Exists(kCategoryName) Then CreateCounters() End If
The CreateCounters is a method that creates the counters and the category. It can only be called if the category is not already existing (otherwise, it raises an exception). The code of the CreateCounters method is:
Dim objCounters As New CounterCreationDataCollection Dim objCounterData As CounterCreationData 'Create a first counter objCounterData = New CounterCreationData(kCounter1Name, _ "The first counter we have created.", _ PerformanceCounterType.NumberOfItems32) objCounters.Add(objCounterData) 'Create a second counter objCounterData = New CounterCreationData(kCounter2Name, _ "The second counter we have created.", _ PerformanceCounterType.NumberOfItems32) objCounters.Add(objCounterData) 'Create a new category to hold our counters PerformanceCounterCategory.Create(kCategoryName, _ "Demo for Level Extreme .Net magazine", _ objCounters)
This code is pretty straight forward:
- A counter (objCounterData) is instantiated. The first parameter is the name of the counter that will be used to it later. The second parameter is the description viewable in some tools. The last parameter is the type of counter. A list of 28 types is available. I suggest you see the documentation to find the one you need.
- The counter is added to the collection (objCounters).
- A category is created and filled with the counters just created.
Once the counters are created, we can start using them right away. This is the code you will find in one of the 2 buttons:
'Increments the counter named "Counter1" Dim objCounter As New PerformanceCounter(kCategoryName, kCounter1Name, False) objCounter.Increment()
Out of the 6 constructor’s overrides, we have to use one that let us create a writable instance (readOnly parameter). The Increment method of the counter object can then be used to increment the value by 1. If you wish to increment using another value, you can use the IncrementBy method which accepts a value as its only parameter.
The second application: Decreasing counters
The second application is even easier.
Figure 2: The second application
At the top of the code, we need the same 3 constants we had in the first application.
Then a single event procedure is used for both buttons. The first part of the procedure is to detect which button was pressed:
Dim strCounterName As String If sender Is btnDecrease1 Then strCounterName = kCounter1Name Else strCounterName = kCounter2Name End If
Then, the corresponding counter (using the same constructor as in the previous example) can be instantiated and decrease by one:
Try Dim objCounter As New PerformanceCounter( kCategoryName, strCounterName, False) If objCounter.RawValue > 0 Then objCounter.Decrement() End If Catch ex As System.InvalidOperationException Microsoft.VisualBasic.Beep() Catch ex As Exception MessageBox.Show(ex.ToString) End Try
Appropriate exception handling is required in case counters do not exist.
Notice that if you need to decrease the counter by a value different then 1, you can use the IncrementBy method with a negative argument.
The third application: Reading values
This last application has 2 features.
Figure 3: The third application
The first feature reads the values of both counters and displays the values into labels:
Try Dim objCounter1 As New PerformanceCounter(kCategoryName, kCounter1Name) lblCounter1.Text = objCounter1.RawValue.ToString Catch ex As System.InvalidOperationException lblCounter1.Text = "Counter1 does not exist" Catch ex As Exception MessageBox.Show(ex.ToString) End Try
Notice that this time; a read-only instance is enough for our needs (no value for the third argument).
The second feature allows us to completely delete the category and all its counters from the system:
If PerformanceCounterCategory.Exists(kCategoryName) Then PerformanceCounterCategory.Delete(kCategoryName) End If
If you don’t need to update the counters, you could use a different constructor to read a performance counter available on a different computer:
Dim objCounter1 As New PerformanceCounter( _ kCategoryName, kCounter1Name, "", "ComputerName")
VS.Net IDE and the performance counters
Have you ever saw the Performance Counters section in the Server Explorer of Visual Studio .Net?
Figure 4: VS.Net IDE
After you ran the first application, the category and its 2 counters were created and will be displayed there until you delete them. Instead of creating the instances by code like we did, we could have dragged one of the counters directly on a form. It is not my favorite option and exception handling is harder.
The Performance application
Another tool you can use to monitor any counters including your own, is the Performance application available from the “Administrative tools”.
Figure 5: The Performance application
Creating your custom performance counters is really easy. Monitoring them is also easy (you don’t even need to write code if you want to use the Performance application provided by Windows).
I hope you appreciated the topic and see you next month.