Sugerencias para el registro de ULS

Actualizado el 4-2-2011: recomiendo ver el ejemplo actualizado sobre este tema en http://blogs.msdn.com/b/sharepoint_sp/archive/2011/03/21/sugerencias-para-el-registro-de-uls-parte-2.aspx. El nuevo ejemplo es mejor y más funcional.

Al agregar algunos registros de ULS a un proyecto reciente, observé un efecto secundario un poco molesto.  En los registros de ULS, el área se mostraba como "Desconocida".  Sé que algunos aspectos de este tema se han tratado en otros lugares, pero quería realizar una entrada de blog rápida que describiera la manera más conveniente que encontré para solucionar el problema (mucho menos complicada que algunas de las otras soluciones que he visto).  Una cosa que vale la pena señalar es que si no desea realizar este procedimiento, creo que el marco de registro que el equipo de procedimientos recomendados colocó en CodePlex realiza esta tarea por usted.  Pero suelo escribir mi propio código siempre que sea posible, por lo que describiré brevemente la solución aquí.

Lo primero que se debe tener en cuenta es que la mayoría de la documentación del SDK se basa en la idea de crear una nueva SPDiagnosticsCategory.  El constructor de una nueva instancia de la clase permite proporcionar el nombre de categoría. Al hacerlo, en la columna Categoría del registro de ULS, aparecerá el nombre de la categoría personalizada que desee usar.  En la mayoría de los casos, si realiza su propio registro personalizado, deseará tener también un área personalizada que acompañe a las categorías personalizadas.  Lamentablemente, el procedimiento que indica el SDK para realizar esta tarea es considerablemente más complejo, porque no permite usar un constructor simple para crear una nueva área y usarla; debe escribir su propia clase que derive de SPDiagnosticsServiceBase.

La forma que elegí para implementar todo este procedimiento es crear un archivo CS que contenga la clase de registro y la clase base de servicio de diagnóstico.  Primero comenzaré con la clase base de diagnóstico (debajo pegué la clase completa) y, a continuación, proporcionaré una guía sobre todo aquello que se debe tener en cuenta:

    public class SteveDiagnosticService : SPDiagnosticsServiceBase

    {

 

        private const string LOG_AREA = "Steve Area";

 

 

        public enum LogCategories

        {

            SteveCategory

        }  

 

 

 

        public SteveDiagnosticService()

            : base("Steve Diagnostics Service", SPFarm.Local)

        {

        } 

 

 

 

        public SteveDiagnosticService(string name, SPFarm parent)

            : base(name, parent)

        {

        } 

 

 

 

        protected override bool HasAdditionalUpdateAccess()

        {

            return true;

        }

 

 

        public static SteveDiagnosticService Local

        {

            get

            {

                return SPDiagnosticsServiceBase.GetLocal<SteveDiagnosticService>();

            }

        }  

 

 

 

        public void LogMessage(ushort id, LogCategories LogCategory, TraceSeverity traceSeverity,

            string message, params object[] data)

        {

 

            if (traceSeverity != TraceSeverity.None)

            {

                SPDiagnosticsCategory category

                 = Local.Areas[LOG_AREA].Categories[LogCategory.ToString()];

                Local.WriteTrace(id, category, traceSeverity, message, data);

            }

 

        }

 

 

        protected override IEnumerable<SPDiagnosticsArea> ProvideAreas()

        {

 

            List<SPDiagnosticsCategory> categories = new List<SPDiagnosticsCategory>();

 

            categories.Add(new SPDiagnosticsCategory(

             LogCategories.SteveCategory.ToString(),

             TraceSeverity.Medium, EventSeverity.Information));

 

            SPDiagnosticsArea area = new SPDiagnosticsArea(

             LOG_AREA, 0, 0, false, categories);

 

            List<SPDiagnosticsArea> areas = new List<SPDiagnosticsArea>();

 

            areas.Add(area);

 

            return areas;

        }

    }

 

Ahora veamos las partes interesantes:

private const string LOG_AREA = "Steve Area";

Aquí es donde defino el nombre del área que voy a escribir en el registro de ULS.

public enum LogCategories

{

SteveCategory

}    

Esta es la lista de categorías que voy a agregar al área personalizada.  En este caso, solo voy a usar una categoría con esta área; pero si desea usar varias, solo deberá expandir el contenido de esta enumeración.

public void LogMessage(ushort id, LogCategories LogCategory, TraceSeverity traceSeverity,

string message, params object[] data)

{

if (traceSeverity != TraceSeverity.None)

{

SPDiagnosticsCategory category

= Local.Areas[LOG_AREA].Categories[LogCategory.ToString()];

 

Local.WriteTrace(id, category, traceSeverity, message, data);

}

}

 

Este es uno de los dos métodos importantes que voy a implementar; es donde realmente se escribe en el registro de ULS.  La primera línea es donde obtengo SPDiagnosticCategory y, al hacerlo, hago referencia al área a la que pertenece.  En la segunda línea, simplemente llamo al método de clase base en la clase SPDiagnosticsServiceBase local para escribir en el registro de ULS. Como parte de esta tarea, paso la categoría que está asociada con el área.

protected override IEnumerable<SPDiagnosticsArea> ProvideAreas()

{

 

List<SPDiagnosticsCategory> theCategories = new List<SPDiagnosticsCategory>();

 

theCategories.Add(new SPDiagnosticsCategory(

             LogCategories.SteveCategory.ToString(),

             TraceSeverity.Medium, EventSeverity.Information));

 

SPDiagnosticsArea theArea = new SPDiagnosticsArea(

             LOG_AREA, 0, 0, false, theCategories);

 

List<SPDiagnosticsArea> theArea = new List<SPDiagnosticsArea>();

 

theArea.Add(area);

 

return theArea;

}

 

En esta invalidación, devuelvo todas las áreas personalizadas a SharePoint.  En este caso, solo usaré un área, así que eso es todo lo que devuelvo.  Además, como mencioné más arriba, solo usaré una categoría personalizada para el área.  Si quisiera usar varias categorías personalizadas, debería: 1) agregarlas a la enumeración que describí anteriormente y 2) agregar cada una de ellas a la instancia de lista theCategories, que definí en este método.

Ese es el truco principal de agregar un área personalizada y conseguir que se muestre en la columna apropiada en el registro de ULS.  La implementación de la clase de registro también es bastante sencilla. Pegaré la parte principal aquí y, a continuación, explicaré un poco más:

    public class Log

    {

 

        private const int LOG_ID = 11100;

 

 

        public static void WriteLog(string Message, TraceSeverity TraceLogSeverity)

        {

            try

            {

                //in this simple example, I’m always using the same category

                //you could of course pass that in as a method parameter too

                //and use it when you call SteveDiagnosticService

                SteveDiagnosticService.Local.LogMessage(LOG_ID,

                    SteveDiagnosticService.LogCategories.SteveCategory,

                    TraceLogSeverity, Message, null);

            }

            catch (Exception writeEx)

            {

                //ignore

                Debug.WriteLine(writeEx.Message);

            }

        }

    }

 

A continuación, el código es bastante fácil de implementar desde los métodos que hacen referencia a él.  Dado que WriteLog es un método estático, mi código solo es Log.WriteLog("This is my error message", TraceSeverity.Medium); por ejemplo.  Entonces, en este ejemplo, se crea en el registro de ULS una entrada en el área "Steve Area" y la categoría "SteveCategory" con el mensaje "This is my error message".

Esta entrada de blog es una traducción. Puede consultar el artículo original en Tips for ULS Logging