Using Feature Receivers to Configure Diagnostic Areas and Categories

Typical Goals

SharePoint 2010 provides a default set of diagnostic areas and categories that relate to different features and aspects of the product. Typically, system administrators use these areas and categories to restrict what gets written to the event log and the trace log. For example, the administrator might choose to allow verbose logging for categories that are of particular concern, while restricting logging for other areas to only high severity items.

It is strongly recommended that you do not use the built-in areas and categories to log events from your custom applications. Instead, you should create your own areas and categories to enable system administrators to manage diagnostic logging from your application alongside the log entries generated by SharePoint itself.

Solution

Create a farm-scoped feature and add a feature receiver class. Within the feature receiver class, override the FeatureActivated and FeatureDeactivating methods. Use the DiagnosticsAreaCollection class to create and register your custom areas and categories.

Note

Why should you use a farm-scoped feature to configure diagnostic areas and categories for your solution? Suppose your solution consists of features that are scoped to site collection level or the Web application level. An administrator can deploy and retract these features to multiple site collections or Web applications across the server farm. By using a farm-scoped feature to configure areas and categories, you ensure that your areas and categories are available to any feature after your solution is activated, and that the configured areas and categories are not removed until the solution is retracted. A farm-scoped feature automatically activates when the solution is deployed, and it deactivates when the solution is retracted. Security restrictions prevent writing to Farm configuration from the FeatureActivated or FeatureDeactivating events of a site or web scoped feature deployed to a content web. In these circumstances you must use FeatureInstalled and FeatureUninstalling, which execute under the timer process at a higher permission level.

After you configure your diagnostic areas and categories, you can use these values in your code when you write to the event log or the trace log. System administrators can also throttle logging by severity for each of your areas and categories.

Configuring Diagnostic Areas and Categories

The following code shows an example of how to configure an area and some categories in a feature receiver class. Suppose you are deploying a Web Part that enables your users to interact with a Customer Relationship Management (CRM) system. This example registers a new area named CRM. The area contains two categories, LostSale and TransactionError. The feature receiver class is split into three areas for readability.

First, the class includes a helper property to build the collection of areas and categories. This is used both when the feature is activated and when the feature is deactivated.

using Microsoft.Practices.ServiceLocation;
using Microsoft.Practices.SharePoint.Common.ServiceLocation; 
using Microsoft.Practices.SharePoint.Common.Logging;

[Guid("8b0f085e-72a0-4d9f-ac74-0038dc0f6dd5")]
public class MyFeatureReceiver : SPFeatureReceiver
{ 
  // This helper property builds a collection of areas and categories.
  DiagnosticsAreaCollection _myAreas = null;
  DiagnosticsAreaCollection MyAreas
  {
    get
    {
      if (_myAreas == null)
      {
        _myAreas = new DiagnosticsAreaCollection();
        DiagnosticsArea crmArea = new DiagnosticsArea("CRM");
                
        crmArea.DiagnosticsCategories.Add(new DiagnosticsCategory(
            "LostSale", EventSeverity.Warning, TraceSeverity.Medium));
        crmArea.DiagnosticsCategories.Add(new DiagnosticsCategory(
            "TransactionError", EventSeverity.Error, TraceSeverity.Medium));
        
        _myAreas.Add(crmArea);
      }
      return _myAreas;
    }
  }

Next, the FeatureActivated method retrieves the collection of areas and categories and writes the collection to configuration settings.

 
  // Use the FeatureActivated method to save areas and categories 
  // to configuration settings.
  public override void FeatureActivated(SPFeatureReceiverProperties properties)
  {
    IConfigManager configMgr =
        SharePointServiceLocator.GetCurrent().GetInstance<IConfigManager>();
    
    DiagnosticsAreaCollection configuredAreas = 
        new DiagnosticsAreaCollection(configMgr);

    foreach (DiagnosticsArea newArea in MyAreas)
    {
      var existingArea = configuredAreas[newArea.Name];

      if (existingArea == null)
      {
        configuredAreas.Add(newArea);
      }
      else
      {
        foreach (DiagnosticsCategory c in newArea.DiagnosticsCategories)
        {
          var existingCategory = existingArea.DiagnosticsCategories[c.Name];
          if (existingCategory == null)
          {
            existingArea.DiagnosticsCategories.Add(c);
          }
        }
      }
    }
    configuredAreas.SaveConfiguration();
  }

Finally, the FeatureDeactivating method retrieves the collection of areas and categories and removes them from the configuration settings.

  // Use the FeatureDeactivating method to remove areas and categories 
  // from configuration settings.
  public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
  {
    IConfigManager configMgr = 
        SharePointServiceLocator.GetCurrent().GetInstance<IConfigManager>();
    DiagnosticsAreaCollection configuredAreas = 
        new DiagnosticsAreaCollection(configMgr);

    foreach (DiagnosticsArea area in MyAreas)
    {
      DiagnosticsArea areaToRemove = configuredAreas[area.Name];

      if (areaToRemove != null)
      {
        foreach (DiagnosticsCategory c in area.DiagnosticsCategories)
        {
          var existingCat = areaToRemove.DiagnosticsCategories[c.Name];
          if (existingCat != null)
          {
            areaToRemove.DiagnosticsCategories.Remove(existingCat);
          }
        }
        if (areaToRemove.DiagnosticsCategories.Count == 0)
        {
          configuredAreas.Remove(areaToRemove);
        }
      }
    }
    configuredAreas.SaveConfiguration();
  }
}

Note

In some circumstances, different solutions may create duplicate categories. In the preceding code example, there is a risk that you will remove a category that is still in use by another application in the FeatureDeactivating method, because any duplicated categories will be removed. To prevent problems with duplicate categories, you may instead choose to throw an exception if a duplicate category is found during installation.

For more information about how to manage diagnostic areas and categories, see Managing Custom Areas and Categories.

Registering Event Sources for Diagnostic Areas

When you use the SharePoint Logger to create new diagnostic areas, you must create a corresponding event source for each diagnostic area on each WFE server in your farm (or on any other server where your code will execute). This allows you to specify the new diagnostic areas when you write to the Windows event log.

Event sources are defined in the local registry of each computer. Because you must write to the registry to create new event sources, this procedure requires an account with high privileges. There are two principal approaches that you can use to register event sources:

  • You can manually run a batch file or PowerShell script on each WFE server.
  • You can create a timer job that executes on each WFE server.

The SharePoint Logger provides a convenience method to help register event sources. The static DiagnosticsAreaEventSource.EnsureConfiguredAreasRegistered method iterates through all the diagnostic areas in configuration settings, checks to see whether each diagnostic area is already registered as an event source, and registers a new event source if required. You can call this method from your PowerShell script or your timer job, as required.

Usage Notes

SharePoint 2010 allows you to create your own custom categories under built-in areas. However, this is not a recommended approach. You should create custom areas for your custom code.