WebMon: A SCOM Management Pack for Basic Web Site Monitoring, Configured with a Single XML File, Part I

The native Web Application monitoring capabilities of SCOM are impressive to say the least, and provide excellent functionality for in-depth monitoring of complex web application transactions.   However, the administrative effort required to configure web application monitoring makes the implementation less than ideal for wide-scale basic web site monitoring.  In most cases, required web monitoring would entail monitors just for status code, reachability, response time, and perhaps some other checks like certificate validity.  I wanted to create a custom management pack to implement these monitors, with a minimal degree of configuration effort.   While researching available options, I came across a post by Russ Slaten describing a way to utilize the Microsoft SystemCenter WebApplication Library implementation to accomplish a similar goal.  

However, I wanted to take it a step further.  The key decision point in my design approach was that I wanted to be able to deploy a configuration file (in XML format) to each watcher node involved and define the URL’s and monitoring properties in that file.   I have completed this management pack, and I’m quite happy with it thus far.   I’ve described the Management Pack and development process below.

The WebMon MP, Design and Development

When you create a Web Application monitor in the SCOM GUI, a whole suite of management pack objects are created.  Firstly, two classes are created: one for the watcher node and one for the web application perspective, with a hosting relationship between the two.   Then, a composite data source is created, consisting of a timer and an URLProbe from the Microsoft System Center Web Application Library.  The URL Probe contains configuration items like the request header, the authentication settings, and a set of warning and error criteria.   Building from there, a set of MonitorTypes are created that depend on the URL Probe and implement ConditionDetection rules to expose state to Monitors.   Monitors, which utilize the MonitorTypes, and Rules, which utilize the DataSource directly, are also created in accordance with the chosen configuration.   One thing to note is that the configuration defined in the URL probe is static, except for the actual URL, which is fed as a variable to facilitate multiple requests in a single Web Application Perspective.   In order to accomplish the goal of a single set of entities that allowed dynamic monitoring configuration (discovered from a configuration file), my plan was to replace these static configuration items (such as response time threshold) with variables. 

To start with, I replicated the hosted class structure, because I wanted to make sure that each monitored URL request maintained distinct state, with support for rolling up to the watcher node with dependency monitors.   I created two clasess: WebMon.Class.WatcherNode and WebMon.Class.Request.  I wanted to use properties on the Class objects as variable storage, so that a script discovery could discover the chosen configuration variables from an XML file, populate the class parameters with the configuration variables, and then pass those variables to the DataSource via the MonitorTypes.   It took me a little while to work out what configuration parameters should be dynamically loaded, but I eventually settled on this list:

Watcher Node: 
 – Configuration File
Request:
  – URL
 – Polling Interval
 – Retry Count
 – Status Code Value (to alert if the status code is greater than)
 – ResponseTimeThreshold

I then created my initial XML file, and created a script discovery that parses the XML file and creates the Watcher Node and Request Objects.    The discovery is disabled by default and targeted to the Windows Servers class.   Additionally, the first argument accepted by the discovery script is the path to the configuration file.  So, to discover a Watcher Node, the discovery just needs to be enabled through an override, and if the configuration file is in a non-default location, that path can be overridden as well.   There’s a Microsoft article on using a script for discovery here.  To utilize an XML file however, my discovery script first checks for the existence of the XML configuration file and creates the Watcher Node object:

If (oFso.FileExists(sConfigFile)) Then
                       On Error Resume Next
                        set oInst = oDiscoveryData.CreateClassInstance(“$MPElement[Name=’WebMon.Class.WatcherNode’]$”)
                        call oInst.AddProperty(“$MPElement[Name=’Windows!Microsoft.Windows.Computer’]/PrincipalName$”, TargetComputer)
                        call oInst.AddProperty(“$MPElement[Name=’WebMon.Class.WatcherNode’]/ConfigFile$”, sConfigFile)
                        call oInst.AddProperty(“$MPElement[Name=’System!System.Entity’]/DisplayName$”, “WebMon Watcher Node”)
                        call oDiscoveryData.AddInstance(oInst)

Then, the discovery attempts to load the XML file, loop through the requests, and create the Request (or Secure Request) objects:

if oXMLDoc.load(sConfigFile) then
For each xNode in oXMLDoc.selectsinglenode(“.//requests”).childNodes
  if xNode.nodeName = “request” then
  RequestURL = xnode.selectsinglenode(“.//requesturl”).text
  RespTimeThresh = xnode.selectsinglenode(“.//responsetimethreshold”).text 
  PollingInterval = xnode.selectsinglenode(“.//pollinginterval”).text
  RetryCount = xnode.selectsinglenode(“.//retrycount”).text
  StatusCodeValue = xnode.selectsinglenode(“.//statuscodevalue”).text  
  UseNTLM = xnode.selectsinglenode(“.//usentlm”).text 
  if lcase(cstr(UseNTLM & “”)) = “true” then
  set oInst = oDiscoveryData.CreateClassInstance(“$MPElement[Name=’WebMon.Class.SecureRequest’]$”)
  call oInst.AddProperty(“$MPElement[Name=’Windows!Microsoft.Windows.Computer’]/PrincipalName$”, TargetComputer)
  call oInst.AddProperty(“$MPElement[Name=’WebMon.Class.SecureRequest’]/URL$”, RequestURL)    call oInst.AddProperty(“$MPElement[Name=’WebMon.Class.SecureRequest’]/Interval$”, PollingInterval)   call oInst.AddProperty(“$MPElement[Name=’WebMon.Class.SecureRequest’]/ResponseTimeThreshold$”, RespTimeThresh) 
  call oInst.AddProperty(“$MPElement[Name=’WebMon.Class.SecureRequest’]/RetryCount$”, RetryCount)   call oInst.AddProperty(“$MPElement[Name=’WebMon.Class.SecureRequest’]/StatusCodeValue$”, StatusCodeValue)  
  call oInst.AddProperty(“$MPElement[Name=’System!System.Entity’]/DisplayName$”, “Request: ” & RequestURL)  
  call oDiscoveryData.AddInstance(oInst)
  else
  set oInst = oDiscoveryData.CreateClassInstance(“$MPElement[Name=’WebMon.Class.Request’]$”)
  call oInst.AddProperty(“$MPElement[Name=’Windows!Microsoft.Windows.Computer’]/PrincipalName$”, TargetComputer)
  call oInst.AddProperty(“$MPElement[Name=’WebMon.Class.Request’]/URL$”, RequestURL)    call oInst.AddProperty(“$MPElement[Name=’WebMon.Class.Request’]/Interval$”, PollingInterval)    call oInst.AddProperty(“$MPElement[Name=’WebMon.Class.Request’]/ResponseTimeThreshold$”, RespTimeThresh)
  call oInst.AddProperty(“$MPElement[Name=’WebMon.Class.Request’]/RetryCount$”, RetryCount)   call oInst.AddProperty(“$MPElement[Name=’WebMon.Class.Request’]/StatusCodeValue$”, StatusCodeValue)  call oInst.AddProperty(“$MPElement[Name=’System!System.Entity’]/DisplayName$”, “Request: ” & RequestURL)  
  call oDiscoveryData.AddInstance(oInst)
  end if
 End if
Next
End if

I added a bit of data validation to the actual script to work around potential blank values, but this covers the basic methodology. 

Once the discovery was determined to work as expected, I moved on to the monitoring implementation, which took me much longer than expected, largely due to difficulty in debugging.   I created the Composite DataSource, as described in Russ Slaten’s post on the topic, and then began a process of trial and error determining which configuration values I could substitute with variables.  Fortunately, those configuration values most likely to vary (retry count, thresholds, etc), can be substituted with variables.   However, a few that I was hoping to populate dynamically would not allow variables.  These were the operator used in status code comparisons (I had hoped to be able to define an operator such as “greaterthan” or “notequal” in the configuration file for each request), and the authentication scheme.  I wasn’t too concerned about the status code comparison operator, because in most basic web monitoring scenarios, it’s safe to assume that a “greater than” operator should be used  (i.e. “greater than 399”).  What was more concerning was the Authentication Scheme, because I wanted the management pack to support monitoring of anonymous sites as well as secured intranet sites.  I eventually decided that the best way to deal with the requirement for a static definition of the Authentication Scheme was to add a new class, named WebMon Secure Request, for requests that require NTLM/integrated authentication.   I created the class, with identical properties to the WebMon Request  class, and modified the discovery script to assign requests to the classes based on the value of a Boolean element in the configuration file (named: usentlm).   This meant duplicating the data sources (with different settings for authentication) and MonitorTypes, monitors, and rules, but it seemed like the best way to maintain the desired functionality. 

I gave some consideration to which monitors and performance collection rules best represented the level of web monitoring suited by this Management Pack (which was never intended to replace the comprehensive functionality of the standard SCOM Web Application Monitoring implementation), and settled on the following list:

Monitors:

  • DNS Resolution Failure
  • Status Code
  • Reachable
  • Error Code
  • CA Untrusted
  • Certificate Expired
  • Certificate Invalid
  • Response Time

Rules

  • Response Time Performance Collection

For each of the monitors, for each of the two classes, I created a MonitorType utilizing the class’s composite data source, with appropriate criteria evaluation and severity settings.   I also created an aggregate monitor to simplify alerting, as well as dependency monitors on the Watcher Node class to represent the overall status of all monitored requests. 

I also created a set of state and performance views (nested under the Web Application folder in the UI), and embarked on a sequence of testing to confirm that each of the monitors and rules performed as expected.  After the dust settled, here’s an overview of what the management pack looked like:

The configuration file (webmonconfig.xml) :

Inspecting the Watcher Node class in a diagram view:

The Health Monitor for a request:

And the Response Time performance view:

In my next post, I’ll provide a link to download the MP and instructions on deploying it.

Advertisement

About Kristopher Bash
Kris is a Senior Program Manager at Microsoft, working on UNIX and Linux management features in Microsoft System Center. Prior to joining Microsoft, Kris worked in systems management, server administration, and IT operations for nearly 15 years.

One Response to WebMon: A SCOM Management Pack for Basic Web Site Monitoring, Configured with a Single XML File, Part I

  1. Pingback: WebMon: A SCOM Management Pack for Basic Web Site Monitoring, Configured with a Single XML File, Part II « Operating-Quadrant

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: