Unified Logging Service Class

Looking for a simple class to add the ability to write to the Unified Logging Service (ULS) for your SharePoint 2010 project? Then the following should provide a good starting point for you.

Full source code for this example is available to download from here.

First things first, create a new class library project and add a class called Logger. Also add a couple of references to your project.

  • Microsoft.SharePoint
  • System.Web

Next, have your class inherit from the SharePoint class Microsoft.SharePoint.Administration.SPDiagnosticsServiceBase.

[System.Runtime.InteropServices.GuidAttribute("FBAF2022-DB19-4d2b-A029-948B747A4045")]
public class Logger : SPDiagnosticsServiceBase
{
}


Before we start implementing the methods for this class, lets add some additional classes that will be used by the Logger class.

Whenever you write an event to the ULS you have options for specifying the event identifier, category and the error level. To cater for this, create three new classes called EventId, Category and ErrorLevel.

Each of these classes will contain an enumeration of available options. For example, take a look at the error level class:

public enum ErrorLevel
{
    Medium = 10,
    High = 20,
    Monitorable = 30,
    Unexpected = 40
}

This will provide four categories to log events against. You can of course add to this enumeration as you see fit.

The remaining two class files should look something like the following:

public enum EventId
{
    None = 0,
    Information = 100,
    Error = 200
}
 
public enum CategoryId
{
    None = 0,
    Error = 100,
    Auditing = 200,
    Receiver = 300,
    WebPart = 400
}

OK, back to the Logger class.

Add a constant variable to identify the diagnostics area logs will be written against.

private const string DIAGNOSTICS_AREA_NAME = "SharePointStu.SharePoint";

Next, add a couple of constructors for the class.

public Logger()
    : base(DIAGNOSTICS_AREA_NAME, SPFarm.Local)
{
}
 
public Logger(SPFarm farm)
    : base(DIAGNOSTICS_AREA_NAME, farm)
{
}

The first constructor is parameterless and uses the current local farm instance when instantiating. For cases when you need to write to the ULS and are not running under the context of SharePoint, use the second constructor and pass in your own farm object.

One method that should be overridden is ProvideAreas. This method will return a collection of the event and trace logging categories used by this service. We will use it to ensure the custom categories defined in the CategoryId enumeration are registered.

protected override IEnumerable<SPDiagnosticsArea> ProvideAreas()
{
    List<SPDiagnosticsCategory> categories = new List<SPDiagnosticsCategory>();
 
    foreach (string catName in Enum.GetNames(typeof(CategoryId)))
    {
        uint catId = (uint)(int)Enum.Parse(typeof(CategoryId), catName);
        categories.Add(new SPDiagnosticsCategory(catName, TraceSeverity.Verbose, EventSeverity.Error, 0, catId));
    }
 
    yield return new SPDiagnosticsArea(DIAGNOSTICS_AREA_NAME, categories);
}

Another useful method to add to the class is the following class instance indexer:

public SPDiagnosticsCategory this[CategoryId id]
{
    get
    {
        return Areas[DIAGNOSTICS_AREA_NAME].Categories[id.ToString()];
    }
}

This will allow you to get the SPDiagnosticsCategory object relating to one of the category enumeration values.

We’ll now add a few public methods, which will be used to log events to the ULS. The first is for logging errors.

public void LogError(EventId eventId, CategoryId categoryId, ErrorLevel errorId, string infoMessage, Exception ex)
{
    WriteTrace((uint)eventId, Areas[DIAGNOSTICS_AREA_NAME].Categories[categoryId.ToString()], getTraceSeverity(errorId), infoMessage, null);
 
    if (ex != null)
    {
        WriteTrace((uint)eventId, Areas[DIAGNOSTICS_AREA_NAME].Categories[CategoryId.Error.ToString()], getTraceSeverity(errorId), string.Concat(ex.Message, " ", ex.StackTrace), null);
    }
}

This method calls the base WriteTrace method to log the error details to the ULS log.

It also uses a private method called getTraceSeverity to retrieve the corresponding TraceSeverity value.

The other two methods handle the logging of verbose and warning events.

public void LogInfo(EventId eventId, CategoryId categoryId, string infoMessage)
{
    WriteTrace((uint)eventId, Areas[DIAGNOSTICS_AREA_NAME].Categories[categoryId.ToString()], TraceSeverity.Verbose, infoMessage, null);
}
 
public void LogWarning(EventId eventId, CategoryId categoryId, string infoMessage)
{
    WriteTrace((uint)eventId, Areas[DIAGNOSTICS_AREA_NAME].Categories[categoryId.ToString()], TraceSeverity.Unexpected, infoMessage, null);
}

If you want the ability to log events without having to instantiate the Logger class every time, you could add a few static methods which create a new Logger instance each time. In the examples below, these rely on a SharePoint context existing.

public static void LogInfoLocal(EventId eventId, CategoryId categoryId, string infoMessage)
{
    var logger = new Logger();
    logger.LogInfo(eventId, categoryId, infoMessage);
}
 
public void LogWarningLocal(EventId eventId, CategoryId categoryId, string infoMessage)
{
    var logger = new Logger();
    logger.LogWarning(eventId, categoryId, infoMessage);
}
 
public static void LogErrorLocal(EventId eventId, CategoryId categoryId, ErrorLevel errorId, string infoMessage, Exception ex)
{
    var logger = new Logger();
    logger.LogError(eventId, categoryId, errorId, infoMessage, ex);
}

Hopefully this is enough to get you started šŸ™‚

Leave a Reply

Your email address will not be published. Required fields are marked *

Solve the maths problem shown below before posting: *

Follow

Get every new post delivered to your Inbox

Join other followers: