Evjen c32.tex V2 - 01/28/2008 4:05pm Page 1465
Chapter 32: Instrumentation
Event Log Description
Application Enables you to record application-specific events, including whether a certain event
was fired, a page was loaded, or a customer made a specific purchase
Security Enables you to track security-related issues such as security changes and breaches
System Enables you to track system-specific items such as issues that arise with
components or drivers
From your code, you can write to any of the event logs defined in the preceding table as well as to any
custom event logs that you might create. To accomplish this task, create an example ASP.NET page that
contains a multiline TextBox control and a Button control. On the
Button1_Click
event, you register the
text you want placed in the text box directly into the Application event log. Your ASP.NET page should
be similar to what is presented in Listing 32-2.
Listing 32-2: Writing to the Application event log
VB
<%@ Page Language="VB" %>
<%@ Import Namespace="System.Diagnostics" %>
<script runat="server">
Protected Sub Page_Load(ByVal sender As Object, _
ByVal e As System.EventArgs)
If Not EventLog.SourceExists("My Application") Then
EventLog.CreateEventSource("My Application", "Application")
End If
End Sub
Protected Sub Button1_Click(ByVal sender As Object, _
ByVal e As System.EventArgs)
Dim el As EventLog = New EventLog()
el.Source = "My Application"
el.WriteEntry(TextBox1.Text)
Label1.Text = "ENTERED: " & TextBox1.Text
End Sub
</script>
<html xmlns=" >
<head runat="server">
<title>Working with Event Logs</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:TextBox ID="TextBox1" runat="server" Height="75px"
Continued
1465
Evjen c32.tex V2 - 01/28/2008 4:05pm Page 1466
Chapter 32: Instrumentation
TextMode="MultiLine" Width="250px"></asp:TextBox><br />
<br />
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click"
Text="Submit to custom event log" /><br />
<br />
<asp:Label ID="Label1" runat="server"></asp:Label> </div>
</form>
</body>
</html>
C#
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Diagnostics" %>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
if (!EventLog.SourceExists("My Application"))
{
EventLog.CreateEventSource("My Application", "Application");
}
}
protected void Button1_Click(object sender, EventArgs e)
{
EventLog el = new EventLog();
el.Source = "My Application";
el.WriteEntry(TextBox1.Text);
Label1.Text = "ENTERED: " + TextBox1.Text;
}
</script>
Again, for this to work, you must import the
System.Diagnostics
namespace. In the
Page_Load
event
of the page, ASP.NET is checking whether the event source exists for
My Application
.Ifnosuchsource
exists in the Application event log, it is created using the
CreateEventSource()
method.
el.CreateEventSource("My Application", "Application")
The first parameter of the method takes the name of the source that you are creating. T he second param-
eter of this method call takes the name of the event log that you are targeting. After this source has
been created, you can start working with the
EventLog
object to place an e ntry into the system. First,
the
EventLog
object is assigned a source. In this case, it is the newly created
My Application
.Usingthe
WriteEntry()
method, you can write to the specified event log. You can also assign the source and the
message within the
WriteEntry()
method in the following manner:
el.WriteEntry("My Application", TextBox1.Text);
The ASP.NET page produces something similar to what is illustrated in Figure 32-3.
After this is done, you can look in the Event Viewer and see your entry listed in the Application event
log. Figure 32-4 illustrates what happens when you double-click the entry.
1466
Evjen c32.tex V2 - 01/28/2008 4:05pm Page 1467
Chapter 32: Instrumentation
Figure 32-3
Figure 32-4
1467
Evjen c32.tex V2 - 01/28/2008 4:05pm Page 1468
Chapter 32: Instrumentation
Later in this chapter, you see some of the automatic ways in which ASP.NET can record events for you in
the event log and in some other data stores (such as Microsoft’s SQL Server). Next, it is time to turn your
attention to working with performance counters.
Using Performance Counters
Utilizing performance counters is important if you want to monitor your applications as they run. What
exactly is monitored is up to you. A plethora of available performance counters are at your disposal in
Windows and you will find that there are more than 60 counters specific to ASP.NET.
Viewing Performance Counters Through
an Administration Tool
You can see these performance counters by opening the Performance dialog found in the Control Panel
and then Administration Tools if you are using Windows XP. If you are using Windows Vista, select
Control Panel ➪ System and Maintenance ➪ Performance Information and Tools ➪ Advanced Tools ➪
Open Reliability and Performance Monitor. Figure 32-5 shows the dialog opened in Windows Vista.
Figure 32-5
1468
Evjen c32.tex V2 - 01/28/2008 4:05pm Page 1469
Chapter 32: Instrumentation
Clicking the plus sign in the menu enables you to add more performance counters to the list. You will
find a number of ASP.NET–specific counters in the list illustrated in Figure 32-6.
Figure 32-6
The following list details some of the ASP.NET–specific performance counters that are at your disposal
along with a definition of the counter (also available by checking the Show Description check box in Vista
from within the dialog).
❑ Application R estarts: Number of times the application has been restarted during the Web
server’s lifetime.
❑ Applications Running: Number of currently running Web applications.
❑ Audit Failure Events Raised: Number of audit failures in the application since it was started.
❑ Audit Success Events Raised: Number of audit successes in the application since it was started.
❑ Error Events Raised: Number of error events raised since the application was started.
❑ Infrastructure Error Events Raised: Number of HTTP error events raised since the application
was started.
1469
Evjen c32.tex V2 - 01/28/2008 4:05pm Page 1470
Chapter 32: Instrumentation
❑ Request Error Events Raised: Number of runtime error events raised since the application was
started.
❑ Request Execution Time: The number of milliseconds it took to execute the most recent request.
❑ Request Wait Time: The number of milliseconds the most recent request was waiting in the
queue.
❑ Requests Current: The current number of requests, including those that are queued, currently
executing, or waiting to be written to the client. Under the ASP.NET process model, when this
counter exceeds the
requestQueueLimit
defined in the
processModel
configuration section,
ASP.NET begins rejecting requests.
❑ Requests Disconnected: The number of requests disconnecte d because of communication errors
or user terminations.
❑ Requests Queued: The number of requests waiting to be processed.
❑ Requests Rejected: The number of requests rejected because the request queue was full.
❑ State Server Sessions Abandoned: The number of sessions that have been explicitly abandoned.
❑ State Server Sessions Active: The current number of sessions currently active.
❑ State Server Sessions Timed Out: The number of sessions timed out.
❑ State Server Sessions Total: The number of sessions total.
❑ Worker Process Restarts: Number of times a worker process has restarted on the machine.
❑ Worker Processes Running: Number of worker processes running on the machine.
These are the performance counters for just the ASP.NET v2.0.50727 category. Here you will find cate-
gories for other ASP.NET–specific items such as:
❑ ASP.NET
❑ ASP.NET Applications
❑ ASP.NET Apps v1.0.3705.288
❑ ASP.NET Apps v2.0.50727
❑ ASP.NET State Service
❑ ASP.NET v1.0.3705.288
❑ ASP.NET v2.0.50727
Performance counters can give you a pretty outstanding view of what is happening in your application.
The data retrieved by a specific counter is not a continuous thing because the counter is really taking
a snapshot of the specified counter every 400 milliseconds, so be sure to take that into account when
analyzing the data produced.
Building a Browser-Based Administrative Tool
In addition to viewing the performance counters available to you through the Performance dialog,
you can also get at the performance counter values programmatically. This is possible by working
with the
System.Diagnostics
namespace in the .NET Framework. This namespace gives you access to
1470
Evjen c32.tex V2 - 01/28/2008 4:05pm Page 1471
Chapter 32: Instrumentation
performance-counter-specific objects such as the
PerformanceCounterCategory
and
PerformanceCounter
objects.
To show you how to work with these o bjects, this next example creates an ASP.NET page that enables
you to view any value from a performance counter directly in the browser. To accomplish this task, create
a basic ASP.NET page that includes three DropDownList controls, a Button control, and a Label control.
This gives you the results presented in Figure 32-7.
Figure 32-7
Listing 32-3 shows the code required for this figure.
Listing 32-3: Working with performance counters in ASP.NET
VB
<%@ Page Language="VB" %>
<%@ Import Namespace="System.Diagnostics" %>
<%@ Import Namespace="System.Collections.Generic" %>
<script runat="server">
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
If Not Page.IsPostBack Then
Dim pcc As List(Of String) = New List(Of String)
For Each item As PerformanceCounterCategory In _
PerformanceCounterCategory.GetCategories()
pcc.Add(item.CategoryName)
Next
Continued
1471
Evjen c32.tex V2 - 01/28/2008 4:05pm Page 1472
Chapter 32: Instrumentation
pcc.Sort()
pcc.Remove(".NET CLR Data")
DropDownList1.DataSource = pcc
DropDownList1.DataBind()
Dim myPcc As PerformanceCounterCategory
myPcc = New PerformanceCounterCategory(DropDownList1.SelectedItem.Text)
DisplayCounters(myPcc)
End If
End Sub
Protected Sub DisplayCounters(ByVal pcc As PerformanceCounterCategory)
DisplayInstances(pcc)
Dim myPcc As List(Of String) = New List(Of String)
If DropDownList3.Items.Count > 0 Then
For Each pc As PerformanceCounter In _
pcc.GetCounters(DropDownList3.Items(0).Value)
myPcc.Add(pc.CounterName)
Next
Else
For Each pc As PerformanceCounter In pcc.GetCounters()
myPcc.Add(pc.CounterName)
Next
End If
myPcc.Sort()
DropDownList2.DataSource = myPcc
DropDownList2.DataBind()
End Sub
Protected Sub DisplayInstances(ByVal pcc As PerformanceCounterCategory)
Dim listPcc As List(Of String) = New List(Of String)
For Each item As String In pcc.GetInstanceNames()
listPcc.Add(item.ToString())
Next
listPcc.Sort()
DropDownList3.DataSource = listPcc
DropDownList3.DataBind()
End Sub
Protected Sub DropDownList1_SelectedIndexChanged(ByVal sender As Object, _
ByVal e As System.EventArgs)
Dim pcc As PerformanceCounterCategory
pcc = New PerformanceCounterCategory(DropDownList1.SelectedItem.Text)
Continued
1472
Evjen c32.tex V2 - 01/28/2008 4:05pm Page 1473
Chapter 32: Instrumentation
DropDownList2.Items.Clear()
DropDownList3.Items.Clear()
DisplayCounters(pcc)
End Sub
Protected Sub Button1_Click(ByVal sender As Object, _
ByVal e As System.EventArgs)
Dim pc As PerformanceCounter
If DropDownList3.Items.Count > 0 Then
pc = New PerformanceCounter(DropDownList1.SelectedItem.Text, _
DropDownList2.SelectedItem.Text, DropDownList3.SelectedItem.Text)
Else
pc = New PerformanceCounter(DropDownList1.SelectedItem.Text, _
DropDownList2.SelectedItem.Text)
End If
Label1.Text = "<b>Latest Value:</b> " & pc.NextValue().ToString()
End Sub
</script>
<html xmlns=" /><head runat="server">
<title>Working with Performance Counters</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<strong>Performance Object:</strong><br />
<asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="True"
OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged">
</asp:DropDownList><br />
<br />
<strong>Performance Counter:</strong><br />
<asp:DropDownList ID="DropDownList2" runat="server">
</asp:DropDownList><br />
<br />
<strong>Instances:</strong><br />
<asp:DropDownList ID="DropDownList3" runat="server">
</asp:DropDownList><br />
<br />
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click"
Text="Retrieve Value" /><br />
<br />
<asp:Label ID="Label1" runat="server"></asp:Label></div>
</form>
</body>
</html>
C#
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Diagnostics" %>
<%@ Import Namespace="System.Collections.Generic" %>
Continued
1473
Evjen c32.tex V2 - 01/28/2008 4:05pm Page 1474
Chapter 32: Instrumentation
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
List<string> pcc = new List<string>();
foreach (PerformanceCounterCategory item in
PerformanceCounterCategory.GetCategories())
{
pcc.Add(item.CategoryName);
}
pcc.Sort();
pcc.Remove(".NET CLR Data");
DropDownList1.DataSource = pcc;
DropDownList1.DataBind();
PerformanceCounterCategory myPcc;
myPcc = new
PerformanceCounterCategory(DropDownList1.SelectedItem.Text);
DisplayCounters(myPcc);
}
}
void DisplayCounters(PerformanceCounterCategory pcc)
{
DisplayInstances(pcc);
List<string> myPcc = new List<string>();
if (DropDownList3.Items.Count > 0)
{
foreach (PerformanceCounter pc in
pcc.GetCounters(DropDownList3.Items[0].Value))
{
myPcc.Add(pc.CounterName);
}
}
else
{
foreach (PerformanceCounter pc in pcc.GetCounters())
{
myPcc.Add(pc.CounterName);
}
}
myPcc.Sort();
DropDownList2.DataSource = myPcc;
DropDownList2.DataBind();
}
Continued
1474