Instrumentation

Retired Content

This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.

The latest Enterprise Library information can be found at the Enterprise Library site.

In Enterprise Library, the code that raises an event and the code that dictates what actions should occur when the event is raised are separated. The application code that raises the event is referred to as the provider code. The code that responds to the event is referred to as the listener code. This separation allows you to change what happens when a particular event occurs without having to recompile the provider code. However, you still have to recompile the listener code.

The application code raises events when something of interest occurs, such as connecting to a database or logging a message. Raising these events invokes listeners that are associated with the application at run time by reflection. The listeners contain the code that determines what happens when an event is raised, such as logging a message to the event log or incrementing a counter. An application block functions normally if it has no listeners associated with it.

Using Attributes

You need the following three attributes to instrument an application and a listener:

  • [InstrumentationListener]
  • [InstrumentationProvider]
  • [InstrumentationConsumer]

The [InstrumentationListener] attribute appears before the provider class and tells it which listener class to instantiate. The [InstrumentationProvider] attribute appears before the event in the provider code. The provider code is in the application. The [InstrumentationConsumer] attribute appears before the handler method in the listener. The name specified in this attribute must match the name specified in the [InstrumentationProvider] attribute. These attributes are recorded as metadata.

The following example shows the code for instrumenting a listener.

public class MyListener
{
   public MyListener(string instanceName, bool a, bool b, bool c) {}
 
   [InstrumentationConsumer("DbConnect")]
   public void ConnectObserved(object sender, EventArgs e)
   {
      Console.WriteLine("I saw a Database Connect.");
   }
}
Public Class MyListener  Public Sub New(ByVal instanceName As String, ByVal a As Boolean, ByVal b As Boolean, ByVal c As Boolean)  End Sub  <InstrumentationConsumer("DbConnect")> _  Public Sub ConnectObserved(ByVal sender As Object, ByVal e As EventArgs)    Console.WriteLine("I saw a Database Connect.")  End Sub End Class

The following example shows the code for instrumenting the provider.

[InstrumentationListener(typeof (MyListener))]
public class MyApplication
{
  [InstrumentationProvider("DbConnect")]
  public event EventHandler<EventArgs> OnDbConnect;
}
<InstrumentationListener(GetType(MyListener))> _ Public Class MyApplication  <InstrumentationProvider("DbConnect")> _  Public Event OnDbConnect As EventHandler End Class

When the system instantiates the MyApplication class, it examines the attributes to determine whether there is a listener whose type is MyListener and, if there is, it also instantiates that class. Then it examines all the events in the MyApplication instance that are marked with [InstrumentationProvider] attributes; it also looks for methods in the MyListener instance that are marked with [InstrumentationConsumer] attributes. It associates the events and the methods that have the matching "DbConnect" string in their respective attributes. There is a one-to-one correspondence between providers and listeners. There is one provider associated with one listener.

Instrumenting Components

An application can be made up of components, such as databases. If this is the case, the components instead of the application itself should be instrumented. To delegate the responsibility for instrumentation to a component, your application must implement the IInstrumentationEventProvider interface. In the following example, the MyApplication class delegates instrumentation to the MyInstrumentationProvider class. The code for MyListener class is the same as the code used in the previous example.

public class MyApplication : IInstrumentationEventProvider
{
  private MyInstrumentationProvider instrumentationProvider = 
                                             new MyInstrumentationProvider();
 
  public object GetInstrumentationEventProvider()
  {
     return instrumentationProvider;
  }
}
 
[InstrumentationListener(typeof (MyListener))]
public class MyInstrumentationProvider
{
  [InstrumentationProvider("DbConnect")]
  public event EventHandler<EventArgs> OnDbConnect;
 
  public bool IsWired
  {
    get { return OnDbConnect != null; }
  }
}
Public Class MyApplication Implements IInstrumentationEventProvider  Private instrumentationProvider As MyInstrumentationProvider = New MyInstrumentationProvider  Public Function GetInstrumentationEventProvider() As Object    Return instrumentationProvider  End Function End Class <InstrumentationListener(GetType(MyListener))> _ Public Class MyInstrumentationProvider  <InstrumentationProvider("DbConnect")> _  Public Event OnDbConnect As EventHandler  Public ReadOnly Property IsWired() As Boolean    Get      Return Not (OnDbConnect Is Nothing)    End Get  End Property End Class

Usually, the system looks above the first line of the MyApplication class for the [InstrumentationListener] attribute. However, in this case, this attribute is not present. Therefore, when the system sees the IInstrumentationEventProvider interface, it invokes the GetInstrumentationEventProvider method, looks at the attributes of the class corresponding to the type returned by that method, and searches for any [InstrumentationProvider] attributes.

Installing the Instrumentation

The instrumentation in a listener class is annotated with the [HasInstallableResources] attribute. The following example shows the metadata associated with a listener class.

[HasInstallableResources]
[PerformanceCountersDefinition("Enterprise Library Data Counters", "CounterCategoryHelpResourceName")]
[EventLogDefinition("Application", "Enterprise Library Data")]
public class DataInstrumentationListener : InstrumentationListener
{
  [PerformanceCounter("Connections Opened/sec", "ConnectionOpenedCounterHelpResource", PerformanceCounterType.RateOfCountsPerSecond32)]
  EnterpriseLibraryPerformanceCounter connectionOpenedCounter;
}
<HasInstallableResources()> _ <PerformanceCountersDefinition("Enterprise Library Data Counters", "CounterCategoryHelpResourceName")> _ <EventLogDefinition("Application", "Enterprise Library Data")> _ Public Class DataInstrumentationListener Inherits InstrumentationListener   <PerformanceCounter("Connections Opened/sec", "ConnectionOpenedCounterHelpResource", PerformanceCounterType.RateOfCountsPerSecond32)> _   Private connectionOpenedCounter As EnterpriseLibraryPerformanceCounter End Class

The definitions for each type of instrumentation assign the counter to a category and give it a Help resource name for the Help system. There is an optional third parameter that specifies whether there is a single instance or multiple instances of the category. A counter can belong to only one category.

The InstallUtil.exe tool searches each assembly for the [HasInstallableResources] attribute and assigns the counters to the correct categories. Running the InstallServices.bat batch file will invoke the InstallUtil.exe tool and install all the instrumentation. You can also use it to uninstall the instrumentation. Installing instrumentation requires administrative privileges.

If instrumentation is turned off, either through configuration or by omitting the relevant configuration sections, you can use the xcopy command to deploy the application.

Retired Content

This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.

The latest Enterprise Library information can be found at the Enterprise Library site.