.gif) |
n a perfect world, a Web server would never freeze or crash. But they do. Most of the time it's attributed to misbehaving DLLs (such as ISAPI extensions and filters). Features like isolated processes, introduced with Microsoft® Internet Information Server (IIS) 4.0, and automatic service restarts (introduced with IIS 5.0 on Windows® 2000) help to alleviate these problems. A number of companies provide complete monitoring tools for Web services.
The simple monitoring tool I will describe in this article is not intended to replace these tools. I developed it for use on a small Web site when I did not want to go to the expense of buying a full-featured Web monitoring tool. I find this tool very useful in cases when I need to monitor multiple Web server machines in my local setup, especially when installing a third-party monitoring tool is either too expensive or too complicated. The tool can remove a Web server machine from the Windows Load Balancing Service (WLBS) when the Web server on that machine fails to respond. You can also use this tool to distinguish between a Web server that is down and one that is unreachable due to network problems. In addition, the tool showcases some of the technologies in Windows since all the technologies used to develop this tool ship with Windows 2000, or can be downloaded for Windows NT® 4.0.
The monitoring tool is written in JScript® and is driven by an XML file, URLStomonitor.xml, which contains the configuration information. I decided to use XML because it makes the file easy to read, and the readily available XML parser in Microsoft Internet Explorer 5.0 simplifies the implementation. You can automate monitoring using the Windows Task Scheduler, as you'll see later. The following steps represent the process the monitoring tool follows when monitoring a site.
- Reads the XML configuration file that's passed as a command-line argument.
- Parses the XML file and validates the syntax against the provided schema.
- For every site in the file:
- Send a request to the site
- If the site functions correctly, continue with the next site
- Otherwise set a status variable to false
- If the status variable is false:
- Take corrective action
- Send e-mail to notify administrators
- Log events with the event log subsystem as necessary.
The tool is packaged in six files that should be deployed to the same directory: four JScript files (main.js, startServices.js, httpMonitor.js, and mail.js), one XML schema file (monitorSchema.xml), and one Windows script file that wraps everything together. All of the files are available for download from the link at the top of this article.
Let's walk through each of these files and investigate the steps the tool takes during execution, as described earlier.
Configuration and XML Schema Files
The configuration information is maintained in an XML file. This is the only file that needs to be customized every time you deploy the tool. The file is passed as a command-line argument to the tool and can reside anywhere in the file system. The file specifies the name of the sites to monitor, verification information that's compared with the HTML returned by the site to verify that it's running properly, an e-mail notification address for when the site doesn't respond, and whether events should be logged with the Windows logging subsystem.
MonitorSchema.xml is an XML data schema file that serves two purposes. First, it documents the syntax of the configuration file. Second, it is used at runtime by the XML parser to validate a given configuration file. This schema is simple, with nine element types and three attribute types. Three element types are expected to be top-level elements. Figure 1 shows the XML schema.
The LOG element specifies when to log events to the event log. You can configure it to log successful probes, unsuccessful probes, or both. The Schema file specifies that the LOG element expects two attributes. Each attribute is an enumeration that takes two values: true or false. If the attributes are omitted, the tool writes to the log only when there's a failure.
The E-MAIL element contains information regarding e-mail. The tool sends an e-mail message whenever it is forced to restart the Web server. The FROM element determines the e-mail address of the sender as it appears in the e-mail. This should be an address in an existing domain so that certain mail relays don't reject it as spam. The TO elements specify one or more recipients.
The SITE element contains the sites to be probed. For every site, two parameters are specified. The URL element specifies the URL of the site. The MATCH element specifies a regular expression that matches part of the document returned from the server. A probe is considered successful if both the server returns an OK status (code 200), and the pattern in the MATCH element is contained in the returned HTML document. Figure 2 shows an example XML configuration file.
Figure 2 monitors two sites on the local host, one on port 2082 and another one on port 2083. In my example, I match any page that ends with <!--SWTAGOK--></html>. SWTAGOK is a special comment that I appended at the end of the HTML file. This is a good example to showcase the XML CDATA construct. If the CDATA construct had been omitted, the XML parser would confuse the expected data with XML elements. The e-mail element contains the information regarding e-mail notification. In the example, all generated e-mail will appear as sent from panos@acm.org. For every incident, two e-mail messages will be sent, one to panos@acm.org and one to panos@healtheon.com.
Calling the JScript Functions
The Windows script file is another type of XML file that was introduced with Microsoft Windows Script Host (WSH) version 2.0. It supports include statements (in a cleaner way than previous versions did), multiple language engines, type libraries, and multiple jobs in one file. Support for include statements is one of my favorite new features because it makes it easy to structure the scripting code in a reusable fashion. For instance, I have split the four major monitoring components of the tool into four files. The functions in each file could be reused in other situations. Figure 3 shows the Windows script file.
The main.js file contains the main function (which calls the parsing function, calls RestartServices, and so on) and the parsing functionality (see Figure 4). The httpMonitor.js file contains functions that probe the Web server. The startServices.js file contains functions to start and stop the services. Finally, the mail.js file contains functions that send and receive mail. With the exception of the main.js file, the code in the other files is totally reusable. In fact, I use exactly the same code to send e-mail from some of my ASP pages.
Now that you've seen the purpose of each file in the tool, let's take a look at each step of the tool's execution: parsing the configuration file, probing the Web sites, logging events, and sending e-mail notifications.
Parsing the Configuration File
I use the XML parser that ships with Internet Explorer 5.0 to parse the configuration file. The parser is packaged as a COM component that can be created using the Microsoft.XMLDOM ProgID. Parsing the XML file is almost as simple as calling the load method of the object. As I mentioned earlier, this readily available XML parser was one of the main reasons I decided to use XML for the syntax of the configuration file.
The XML-Data Schema file, monitorSchema.xml, drives the parsing of the configuration file. The file contains the rules that the parser uses to determine valid configuration files. In practice, that means that if you make a mistake while editing your configuration file, instead of a cryptic scripting error, you get a syntax error explaining where and why the error appeared. For instance, let's assume that you forgot or misspelled the E-MAIL element. When you run the program, parsing will fail and an event will be recorded, as shown in Figure 5.
.gif) |
Figure 5 A Recorded Error Event |
All this error information is available thanks to the XML DOM XMLDOMParseError object. This object is available from the XMLDOMDocument parseError property when the load or loadXML methods fail. The error object has a number of useful properties. The url and line properties hold the context where the error occurred. The reason property holds the syntax error. Here is the code snippet that raises the exception that leads to the event shown in Figure 5.
if (!xmlTree.load(strFileName)) throw "Failed to load
file as XML.\n" + xmlTree.parseError.url + ":"
+ xmlTree.parseError.line + " " +
xmlTree.parseError.reason;
|
Probing the Web Sites
I would have never attempted to write this tool if the XMLHTTPRequest object was not available. This object provides programmatic functionality that is usually hidden inside Web browsers. The program that uses this object can send POST and GET requests to a Web server and collect the results. The object can be created using the Microsoft.XMLHTTP ProgID.
The object provides five methods, of which open and send are the most useful. The open method specifies what kind of HTTP request should be performed, and provides for asynchronous requests. The send method performs the actual invocation. Upon completion of the method, the status property contains the value returned from the Web server. The responseText property contains the document returned from the server.
The tool considers a site as operating successfully if the request returns a status of 200, and the returned document contains the match string that has been specified in the configuration file. I introduced string matching for cases where partial pages might be returned, leading you to believe that the server had responded properly. For instance, if the Web server is running out of memory, some ASP pages might return ASP error pages. Since a page was delivered over HTTP, these would appear to the user to be successful requests returning from the server with status of 200, but they would fail the string-matching test.
The string you use can be any regular expression. Matching regular expressions is the kind of technology you can reuse rather than building from scratch each time. Luckily, a regular expression object comes with WSH. The following function, CheckIfServiceIsUp, probes a Web site.
function CheckIfServiceIsUp(objShell, strURL,
strToSearchFor, intFlags)
{
var obj = new ActiveXObject("Microsoft.XMLHTTP");
obj.open("GET", strURL, false);
���
obj.send();
���
// Look for the string to search
var re = new RegExp(strToSearchFor, "gi");
if ((obj.status == 200) && (re.test(obj.responseText))) {
// OK
} else {
// PROBLEM
}
}
|
For clarity, I have omitted the code that does the error checking, but you can find the full code in the downloadable source at the link at the top of this article.
If you ever use this component, keep in mind that the current implementation of the HTTPRequest object does not support server-to-server communication. The issues are explained in the Microsoft Knowledge Base article Q237906.
Logging Events
Before the release of WSH 2.0, there was no easy way to log Windows NT events from a scripting language. Many who appreciated the concept of collecting all errors in one place have written custom COM objects that logged events. Luckily, version 2.0 of WSH introduced a new method called LogEvent. The method applies to the WshShell object and permits you to log warning, informational, error, and auditing messages. Here is some sample code that demonstrates how to log events:
var gobjShell = new ActiveXObject("WScript.Shell");
gobjShell.LogEvent(1, "test message");
|
The only shortcoming of the logging method is that all events appear to be coming from the WSH subsystem. I would prefer to be able to specify that the event is coming from the MYWEBMON subsystem.
Sending E-mail Notifications
In addition to logging Windows NT events, the Web monitoring tool e-mails operators when probes are unsuccessful. The COM component I use here is the CDONTS mail component that is available under the ProgID CDONTS.NewMail. The following simple function wraps the CDONTS functionality:
function SendMessage( vsFrom, vsToEmail, vsSubject, vsText)
{
var objNewMail = new ActiveXObject("CDONTS.NewMail")
objNewMail.Send(vsFrom, vsToEmail, vsSubject, vsText, 1)
objNewMail = null
}
|
More advanced functionality, like sending HTML-based e-mail, is available through this component. You can find more details regarding CDONTS in Knowledge Base article Q186204.
Using the Windows Task Scheduler, you can set the Web monitoring tool to run periodically. You can run it by entering this command line into the Run textbox of the Task tab page:
C:\WINNT\system32\wscript.exe //nologo
D:\Program Files\mywebmon\testMon.wsf
c:\inetpub\URLsToMonitor.xml
|
Note that I've used wscript, not cscript. When you use cscript, a command shell pops up momentarily whenever the task runs.
Since the Task Scheduler's lowest frequency is every minute, you cannot run the tool more often than once per minute. To set this frequency, press the Advanced button in the Schedule tab of the task and fill in the dialog boxes as shown in Figure 6.
.gif) |
Figure 6 Task Scheduler |
The Web monitoring tool can be easily extended to add functionality and flexibility. One area that's easily extensible is the XML schema. For instance, you could set an option to terminate IIS when a site does not respond. You could also specify how many times you will try to contact a site before it is declared dead. Currently the configuration file monitors only one URL per site. You could modify the syntax and add support to monitor multiple URLs per site.
An XML text file is a great way to store and retrieve configuration information. However, a text file is not necessarily the best administration interface. You could provide a GUI-based tool to edit the configuration file. The tool could be written in a language like Visual Basic® or it could be Web-based.
Conclusion
This article demonstrates how WSH and some COM objects could be glued together to create a useful site administration tool. Powerful technologies like XML parsing, HTTP requests, event logging, e-mail, and regular expressions were reused as off-the-shelf components in developing the tool. In this case I used JScript to glue the components together, but you could use other scripting languages. The tool was written with fewer than 200 lines of code, and can be put together in a weekend.
|