2006-04-15
| Table of Contents: |
| Rate This Article: | Add This Article To: |
( Page 2 of 2 )
As a programmer and administrator, I'm always monitoring my web servers' resources and applications — almost hourly. If your business requires mission-critical uptime for applications and for services you offer (and aren't they always?), performance monitoring is imperative to keep things running top-notch.
The drawback is that to get access to Windows Performance Monitor, you have to terminal into the tool, or be on a VPN, if you're on the road, or if your business has a heavy-duty multi-layered firewall with heavy restrictions. Wouldn't it be nice to monitor the health of your applications and systems from anywhere, with any device with an Internet connection? You could even use a cell phone or PDA using a web browser, with no special VPN or terminal connections. And, in the process, you'll learn a little more about .NET.
In this article, I show you how to use the .NET framework's Systems.Diagnostic class to do this. This class taps into all of those nifty performance counters using the windows management instrumentation API.
Accessing Performance Counters
Few ASP.NET applications have been written with performance counters for the web. If you have looked for examples, you'll discover that most of them are written as Windows applications.
If you write code for a web-based application using performance counters, the first thing you'll see is a big ugly "Access Denied" error when trying to run it. This is a bit intimidating — you know how .NET and permissions can be — and that is to say, not fun. Before you do anything else, make sure the ASPNET user has access permissions to the System.Diagnostic class. An easy way to do this, without compromising your server's security, is to assign permissions to the Perflib key found in the registry. Open the Run dialog box on your server, type reged32, and select "HKLM > Software > Microsoft > Windows NT > Perflib." Select "Security > Permissions" from the registry editor menu, and add the ASPNET user, giving it full control to this key.
Displaying Performance Counters
Now that permissions are out of the way, let me start with a simple example and build from there.
One of the first useful things to know abour your web or database servers is how much memory is available. With more memory, larger chunks of code and queries can be handled more efficiently. Below is example code for accessing the memory counter and getting the current amount available in megabytes, using the Systems.Diagnostics class.
<%@ Import Namespace="System.Diagnostics" %>
<script language="C#" runat="server">
void Page_Load(Object sender, EventArgs e) {
PerformanceCounter myCounter = new System.Diagnostics.PerformanceCounter();
myCounter.CategoryName = "memory";
myCounter.CounterName = "Available Mbytes";
float cvalue = myCounter.NextValue();
memAvailablemb.Text = cvalue.ToString();
}
</script>
<html>
<head>
<h1>Web Server Stats </h1>
</head>
<body>
<form runat="server">
<table>
<tr>
<td align="right"><b>Available Memory:</b></td><td>
<asp:label id="memAvailablemb" runat="server" /> MB</td>
</tr>
</form>
</body>
</html>
Creating any counter is this easy, as it follows the same syntax. We first set up an instance of the PerformanceCounter class, and then assign values to a few properties. These values are the name of the category the counter is in (i.e. memory assigned to the CategoryName property) and the counter name (i.e. Available Mbytes assigned to the CounterName property). The last thing we do is set up a float type to accept the value returned by the NextValue() method, which is the current value of the counter.
Next, we'll add another useful counter to this example. But first, let's find out how to list all counters for a particular category.
It is useful to know which counters are available in each category. The script below places all single -nstance counters in a list box. That is, executing the script populate the list box control with all the memory counters. Change "memory" in the script to whatever category for which you wish to view counters.
PerformanceCounter[] pcounter;
PerformanceCounterCategory pcategory = new PerformanceCounterCategory("memory");
this.listBox1.Items.Clear();
pcounter = pcategory.GetCounters();
for (int i = 0; i < pcounter.Length; i++)
{
this.listBox1.Items.Add(pcounter [i].CounterName);
}
Let's add a Web Service counter to the previous example, called Current Connections, to see how many connections are present on the web server across all applications. I start by creating another counter instance, as shown below.
PerformanceCounter myCounter2 = new System.Diagnostics.PerformanceCounter(); myCounter2.CategoryName = "Web Service"; myCounter2.CounterName = "Current Connections"; myCounter2.InstanceName = "_Total"; float cvalue2 = myCounter2.NextValue(); cconTotal.Text = cvalue2.ToString();
Some counters have multiple instances, and this one is no exception. We could monitor any one of several web sites we are running on our server. To tell the script which instances, a new property is introduced, called InstanceName; it designates the instance you to monitor. In this example, all instances are being monitored, so the _Total value is used.
This is too fun! Now let's add a counter to monitor the number of milliseconds the last request took handled by the ASP.NET service. If it is low or zero, we know the server isn't under any heavy stress. To add the counter, create a new instance; use the category 'ASP.NET' and counter 'Request Wait Time'. If you're unsure what category names or counter names to use, open Performance Monitor — most of them are the same.
PerformanceCounter myCounter3 = new System.Diagnostics.PerformanceCounter(); myCounter3.CategoryName = "ASP.NET"; myCounter3.CounterName = "Request Wait Time"; float cvalue3 = myCounter3.NextValue(); reqWaitTime.Text = cvalue3.ToString();
So far, the example works well for values that don't change often. What about counters that change almost immediately, and on a continuous basis? These counters are averaged across a certain time, such as Processor Time and Disk Time.
To get an average reading after a specified time for a counter, we use some new methods from the System.Diagnostics class. To illustrate, let's expand on the current example by first adding the counter "Processor Time" in a similar manner to the other counters.
PerformanceCounter myCounter4 = new System.Diagnostics.PerformanceCounter(); myCounter4.CategoryName = "Processor"; myCounter4.CounterName = "% Processor Time"; myCounter4.InstanceName = "_Total"; float cvalue4 = myCounter4.NextValue();
Now we need to get two sample readings and calculate the average between those two readings. To do this, we create couple of instances of the CounterSample class and use the NextSample and Calculate methods to return the result.
CounterSample sample1; CounterSample sample2; double result; sample1 = myCounter4.NextSample(); System.Threading.Thread.Sleep(1000); sample2 = myCounter4.NextSample(); result = CounterSample.Calculate(sample1, sample2); result = System.Math.Round(result,0); cpuTime.Text = result.ToString();
In the code snippet above, two samples are taken. Sample1 and sample2 are two derived types that are created from the NextSample property of the myCounter4 class instance (associated with Processor). A 1000 milliseconds (1 second) is elapsed between the samples before the result is calculated, using the Calculate method of the CounterSample class, and stored to a variable called "result" that is displayed to screen.
If we wanted to add a counter for disk time, we would follow the same steps in taking two samples and displaying the average to the screen.
Figure 1. Web server performance counters
After executing the script on one of my servers, the web page displaying the counter values is shown in Figure 1.
You could expand on the above code by adding conditional statements to indicate threshold levels and to alert you by e-mail. You could even color code it, so that values are displayed green when healthy, or red when critical.
The most important thing, though, is being able to view these stats anywhere there is an Internet connection by not using any ports other than port 80. No firewalls to worry about, no terminal or VPN access needed. What's more, you can even view the stats on a PDA or cell-phone.
![]() |
|


