AddThis Social Bookmark Button

Print

A Quick Introduction to WMI from .NET
Pages: 1, 2

Creating Custom Performance Counters

The examples so far have consumed existing WMI performance counters and events, which is only half the story. You can extend WMI with your own performance counters and event classes and well as instrument your applications configuration data so it's available to an external management tool.



Creating a custom performance counter involves the use of the same System.Diagnostics.PerformanceCounter class we used to read performance data. You can use the static PerformanceCounter.Exists and PerformanceCounter.Create methods to conditionally install the new performance counter. Here is an (admittedly lame) example of a custom performance counter that indicates the number of 7s encountered in an integer parameter to a web service.

// Check if the category already exists or not.
if(!PerformanceCounterCategory.Exists(categoryName))
{
  CounterCreationDataCollection creationData =  
                         new CounterCreationDataCollection();

  // Create two custom counter objects.
  creationData.Add(new CounterCreationData("Number of 7s - Last", 
      "Number of occurences of the number 7 in the last WS call", 
      PerformanceCounterType.NumberOfItems32));


  // Bind the counters to a PerformanceCounterCategory.
  PerformanceCounterCategory myCategory = 
       PerformanceCounterCategory.Create("TestWS Monitor", 
                                         helpInfo, 
                                         creationData);

}

If the counter has not been installed yet, we create a CounterCreationDataCollection that represents the counters in our custom counter category. Deciding how to populate the CounterCreationDataCollection with CounterCreationData instances is the most difficult part. You need to define a PerformanceCounterType for each counter from the predefined list of types that determine how PerformanceCounter.NextValue algorithm works. There are several variations on Average, Difference, Instantaneous, Percentage and Rate types. Here we choose a simple NumberOfItems32 instantaneous type, which not surprisingly holds a simple 32bit value.

PerformanceCounterCategory.Create adds the counter category to the WMI CIM repository. Notice that we didn't register any WMI provider code that supplies the data just the metadata about this counter. Servicing the counter comes later when we create an instance of the PerformanceCounter class with our category and name.

Here is our contrived web service that takes a string parameter and attempts to parse it as an integer. Along the way we test the value provided for the number of 7s and update our custom counter.

[WebMethod]
public int parseInteger(String x)
{
   int val = Int32.Parse(x);
   int count = 0;
   foreach (char c in x.ToCharArray())
   {
      if (c == '7')
         count++;
   }

   PerformanceCounter counter =
      new PerformanceCounter("TestWS Monitor",
	                         "String Length - Last", 
                             false);
   counter.RawValue = count;

   return val;
}

Here we create a writable instance of our PerformanceCounter by passing a false value for the last constructor parameter. If our application has adequate permissions to write performance counters we will successfully construct the PerformanceCounter and can invoke any of the update properties including PerformanceCounter.RawValue, PerformanceCounter.Increment and PerformanceCounter.IncrementBy. The nature of the interaction between the PerformanceCounter.NextValue method and the various update properties depends on the type of performance counter you created.

Exposing Custom Events to WMI

Naturally, the same extensibility is available to the other parts of WMI including events. Exposing interesting application events to WMI lets your users create more sophisticated interactions with your application. Augmenting your exception handling code to fire custom WMI events enables administrators to react to expected and unexpected situations in new and interesting ways. You could print a stack trace to a log file but why not add the ability to notify an interested party with relevant state information as well. That interested party can do just about anything with that notification including emailing you about it!

There are a couple different implementation paths to publish WMI events from your applications. The one I describe below involves creating a class that extends System.Management.Instrumentation.BaseEvent. You can design this event class to consist of whatever fields, properties and methods you feel are appropriate. Any public fields and properties will be published in the CIM at installation time and will be available to event consumers.

using System;
using System.Management;
using System.Configuration.Install;
using System.Management.Instrumentation;

// Specify which namespace the Management 
// Event class is created in
[assembly:Instrumented("Root/Default")]

// Let the system know you will run InstallUtil.exe 
// utility against this assembly -- add reference to 
// System.Configuration.Install.dll
[System.ComponentModel.RunInstaller(true)]
public class CustomEventInstaller : 
                 DefaultManagementProjectInstaller{}

namespace WorkingSetMonitor
{
  // the event class: renamed in the CIM 
  // using ManagedNameAttribute
  [ManagedName("SuperEvent")]
  public class CustomEvent : BaseEvent
  {
    string data; // not exposed to the CIM - its private
    int state;   // exposed via public property
  
    public CustomEvent(string data)
    {
       this.data = data;
    }
  
    public int State
    {
       get { return state; }
       set { state = value; }
    }
  }
}

The InstrumentedAttribute decorates the assembly indicating the WMI namespace to install our metadata into. We include a ManagementProjectInstaller derivative that together with the System.ComponentModel.RunInstaller attribute will help install any custom WMI events in our assembly. The installer code wont run itself however and must be invoked directly or more simply by running the Installutil.exe utility from the .NET framework SDK. Installutil.exe inspects an assemply for the existence of System.ComponentModel.RunInstaller attributes and installs or uninstalls as directed. The System.Management.Instrumentation.ManagedNameAttribute attribute decorates the custom event class to provides a more appropriate event name to WMI than the managed class name.

Our custom event type holds the relevant event state but inherits a Fire method from BaseEvent. Invoking the event is as simple as creating a CustomEvent instance and calling its Fire Method.

CustomEvent customEvent = new CustomEvent("hello");
customEvent.State = 42;
customEvent.Fire();

Hopefully this article surfaced some useful WMI features you can use today with the help of the .NET framework. There's a lot more functionality included in WMI and plenty of .NET framework classes to help with the heavy lifting.

Jim Murphy works for Mindreef, Inc. building web services diagnostic tools.


Return to ONDotnet.com.