{"id":537,"date":"2011-09-16T03:49:40","date_gmt":"2011-09-16T02:49:40","guid":{"rendered":"http:\/\/www.stuartroberts.net\/?p=537"},"modified":"2011-09-16T03:51:35","modified_gmt":"2011-09-16T02:51:35","slug":"unified-logging-service-class","status":"publish","type":"post","link":"http:\/\/www.stuartroberts.net\/index.php\/2011\/09\/16\/unified-logging-service-class\/","title":{"rendered":"Unified Logging Service Class"},"content":{"rendered":"<p>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.<\/p>\n<p>Full source code for this example is available to download from <a href=\"http:\/\/www.stuartroberts.net\/Downloads\/SharePointLogging.zip\">here<\/a>.<\/p>\n<p>First things first, create a new class library project and add a class called Logger.  Also add a couple of references to your project.<\/p>\n<ul>\n<li>Microsoft.SharePoint<\/li>\n<li>System.Web<\/li>\n<\/ul>\n<p>Next, have your class inherit from the SharePoint class  <em>Microsoft.SharePoint.Administration.SPDiagnosticsServiceBase<\/em>.<\/p>\n<pre lang=\"csharp\">\r\n[System.Runtime.InteropServices.GuidAttribute(\"FBAF2022-DB19-4d2b-A029-948B747A4045\")]\r\npublic class Logger : SPDiagnosticsServiceBase\r\n{\r\n}\r\n<\/pre>\n<p><!--more--><br \/>\nBefore we start implementing the methods for this class, lets add some additional classes that will be used by the Logger class.<\/p>\n<p>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.<\/p>\n<p>Each of these classes will contain an enumeration of available options.  For example, take a look at the error level class:<\/p>\n<pre lang=\"csharp\">\r\npublic enum ErrorLevel\r\n{\r\n    Medium = 10,\r\n    High = 20,\r\n    Monitorable = 30,\r\n    Unexpected = 40\r\n}\r\n<\/pre>\n<p>This will provide four categories to log events against. You can of course add to this enumeration as you see fit.<\/p>\n<p>The remaining two class files should look something like the following:<\/p>\n<pre lang=\"csharp\">\r\npublic enum EventId\r\n{\r\n    None = 0,\r\n    Information = 100,\r\n    Error = 200\r\n}\r\n\r\npublic enum CategoryId\r\n{\r\n    None = 0,\r\n    Error = 100,\r\n    Auditing = 200,\r\n    Receiver = 300,\r\n    WebPart = 400\r\n}\r\n<\/pre>\n<p>OK, back to the <em>Logger<\/em> class.<\/p>\n<p>Add a constant variable to identify the diagnostics area logs will be written against.<\/p>\n<pre lang=\"csharp\">\r\nprivate const string DIAGNOSTICS_AREA_NAME = \"SharePointStu.SharePoint\";\r\n<\/pre>\n<p>Next, add a couple of constructors for the class.<\/p>\n<pre lang=\"csharp\">\r\npublic Logger()\r\n    : base(DIAGNOSTICS_AREA_NAME, SPFarm.Local)\r\n{\r\n}\r\n\r\npublic Logger(SPFarm farm)\r\n    : base(DIAGNOSTICS_AREA_NAME, farm)\r\n{\r\n}\r\n<\/pre>\n<p>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 <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/microsoft.sharepoint.administration.spfarm.aspx\" target=\"_blank\">farm<\/a> object.<\/p>\n<p>One method that should be overridden is <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/microsoft.sharepoint.administration.spdiagnosticsservicebase.provideareas.aspx\" target=\"_blank\">ProvideAreas<\/a>.  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 <em>CategoryId<\/em> enumeration are registered.<\/p>\n<pre lang=\"csharp\">\r\nprotected override IEnumerable<SPDiagnosticsArea> ProvideAreas()\r\n{\r\n    List<SPDiagnosticsCategory> categories = new List<SPDiagnosticsCategory>();\r\n\r\n    foreach (string catName in Enum.GetNames(typeof(CategoryId)))\r\n    {\r\n        uint catId = (uint)(int)Enum.Parse(typeof(CategoryId), catName);\r\n        categories.Add(new SPDiagnosticsCategory(catName, TraceSeverity.Verbose, EventSeverity.Error, 0, catId));\r\n    }\r\n\r\n    yield return new SPDiagnosticsArea(DIAGNOSTICS_AREA_NAME, categories);\r\n}\r\n<\/pre>\n<p>Another useful method to add to the class is the following class instance indexer:<\/p>\n<pre lang=\"csharp\">\r\npublic SPDiagnosticsCategory this[CategoryId id]\r\n{\r\n    get\r\n    {\r\n        return Areas[DIAGNOSTICS_AREA_NAME].Categories[id.ToString()];\r\n    }\r\n}\r\n<\/pre>\n<p>This will allow you to get the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/microsoft.sharepoint.administration.spdiagnosticscategory.aspx\" target=\"_blank\">SPDiagnosticsCategory<\/a> object relating to one of the category enumeration values.<\/p>\n<p>We&#8217;ll now add a few public methods, which will be used to log events to the ULS.  The first is for logging errors.<\/p>\n<pre lang=\"csharp\">\r\npublic void LogError(EventId eventId, CategoryId categoryId, ErrorLevel errorId, string infoMessage, Exception ex)\r\n{\r\n    WriteTrace((uint)eventId, Areas[DIAGNOSTICS_AREA_NAME].Categories[categoryId.ToString()], getTraceSeverity(errorId), infoMessage, null);\r\n\r\n    if (ex != null)\r\n    {\r\n        WriteTrace((uint)eventId, Areas[DIAGNOSTICS_AREA_NAME].Categories[CategoryId.Error.ToString()], getTraceSeverity(errorId), string.Concat(ex.Message, \" \", ex.StackTrace), null);\r\n    }\r\n}\r\n<\/pre>\n<p>This method calls the base <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/microsoft.sharepoint.administration.spdiagnosticsservicebase.writetrace.aspx\" target=\"_blank\">WriteTrace<\/a> method to log the error details to the ULS log.<\/p>\n<p>It also uses a private method called <em>getTraceSeverity<\/em> to retrieve the corresponding <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/microsoft.sharepoint.administration.traceseverity.aspx\" target=\"_blank\">TraceSeverity<\/a> value.<\/p>\n<p>The other two methods handle the logging of verbose and warning events.<\/p>\n<pre lang=\"csharp\">\r\npublic void LogInfo(EventId eventId, CategoryId categoryId, string infoMessage)\r\n{\r\n    WriteTrace((uint)eventId, Areas[DIAGNOSTICS_AREA_NAME].Categories[categoryId.ToString()], TraceSeverity.Verbose, infoMessage, null);\r\n}\r\n\r\npublic void LogWarning(EventId eventId, CategoryId categoryId, string infoMessage)\r\n{\r\n    WriteTrace((uint)eventId, Areas[DIAGNOSTICS_AREA_NAME].Categories[categoryId.ToString()], TraceSeverity.Unexpected, infoMessage, null);\r\n}\r\n<\/pre>\n<p>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 <em>Logger<\/em> instance each time.  In the examples below, these rely on a SharePoint context existing.<\/p>\n<pre lang=\"csharp\">\r\npublic static void LogInfoLocal(EventId eventId, CategoryId categoryId, string infoMessage)\r\n{\r\n    var logger = new Logger();\r\n    logger.LogInfo(eventId, categoryId, infoMessage);\r\n}\r\n\r\npublic void LogWarningLocal(EventId eventId, CategoryId categoryId, string infoMessage)\r\n{\r\n    var logger = new Logger();\r\n    logger.LogWarning(eventId, categoryId, infoMessage);\r\n}\r\n\r\npublic static void LogErrorLocal(EventId eventId, CategoryId categoryId, ErrorLevel errorId, string infoMessage, Exception ex)\r\n{\r\n    var logger = new Logger();\r\n    logger.LogError(eventId, categoryId, errorId, infoMessage, ex);\r\n}\r\n<\/pre>\n<p>Hopefully this is enough to get you started \ud83d\ude42<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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 &hellip; <a href=\"http:\/\/www.stuartroberts.net\/index.php\/2011\/09\/16\/unified-logging-service-class\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_mi_skip_tracking":false,"jetpack_post_was_ever_published":false,"jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":[]},"categories":[3],"tags":[35,81,34],"jetpack_publicize_connections":[],"aioseo_notices":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/plx2I-8F","_links":{"self":[{"href":"http:\/\/www.stuartroberts.net\/index.php\/wp-json\/wp\/v2\/posts\/537"}],"collection":[{"href":"http:\/\/www.stuartroberts.net\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.stuartroberts.net\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.stuartroberts.net\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.stuartroberts.net\/index.php\/wp-json\/wp\/v2\/comments?post=537"}],"version-history":[{"count":11,"href":"http:\/\/www.stuartroberts.net\/index.php\/wp-json\/wp\/v2\/posts\/537\/revisions"}],"predecessor-version":[{"id":548,"href":"http:\/\/www.stuartroberts.net\/index.php\/wp-json\/wp\/v2\/posts\/537\/revisions\/548"}],"wp:attachment":[{"href":"http:\/\/www.stuartroberts.net\/index.php\/wp-json\/wp\/v2\/media?parent=537"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.stuartroberts.net\/index.php\/wp-json\/wp\/v2\/categories?post=537"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.stuartroberts.net\/index.php\/wp-json\/wp\/v2\/tags?post=537"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}