Conseils sur la journalisation du service ULS

MISE À JOUR du 04-02-2011 : je vous recommande de regarder l’exemple mis à jour sur cette thématique à l’adresse suivante : http://blogs.msdn.com/b/sharepoint_fr/archive/2011/03/21/conseils-sur-la-journalisation-du-service-uls-2-232-me-partie.aspx. Le nouvel exemple est meilleur et plus fonctionnel.

Lorsque j’ai ajouté de la journalisation ULS à un récent projet, j’ai constaté un effet secondaire ennuyeux.  Dans les journaux ULS, la Zone apparaissait comme étant « Inconnue ».  Je sais que certaines solutions à ce problème ont déjà été trouvées mais je voudrais vous présenter celle que j’ai trouvée, moi, car c’est à n’en pas douter la plus efficace !  Notez bien que si vous n’en voulez pas, l’infrastructure de journalisation, mise en place par l’équipe sur CodePlex dans le cadre des pratiques d’excellence, pourra certainement régler le problème.  Quoi qu’il en soit, j’ai pour habitude d’écrire mon propre code et je vais vous exposer brièvement la solution à laquelle j’ai pensé.

Le premier point à noter est que la documentation du Kit de développement logiciel (SDK) s’appuie sur la notion de création d’une classe SPDiagnosticsCategory.  Le constructeur d’une nouvelle instance de la classe vous permet d’indiquer le nom de la Catégorie et, si vous procédez ainsi, vous voyez tous les noms de Catégorie personnalisée qui s’affichent dans le journal ULS, dans la colonne Catégorie.  Le plus souvent, si vous effectuez votre propre journalisation, vous voudrez aussi qu’une Zone personnalisée aille de pair avec vos Catégories personnalisées.  Malheureusement, la procédure à suivre indiquée dans le SDK est très compliquée car vous ne pouvez pas utiliser un constructeur simple pour créer une Zone et l’utiliser ; il vous faut écrire votre propre classe dérivée de SPDiagnosticsServiceBase.

La solution que j’ai choisie pour implémenter le tout consiste à créer un fichier CS contenant à la fois ma classe de journalisation et ma classe de base du service de diagnostics.  Je commence par la classe de base de diagnostics. Ci-dessous, j’ai collé la classe complète, puis j’ai détaillé les points qui me semblaient dignes d’intérêt :

    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;

        }

    }

 

Jetons à présent un coup d’œil aux parties intéressantes :

private const string LOG_AREA = "Steve Area";

C’est ici que je définis le nom de la Zone que je vais écrire dans le journal ULS.

public enum LogCategories

{

SteveCategory

}    

Voici la liste des Catégories que je vais ajouter à ma Zone personnalisée.  Dans le cas présent, je ne vais utiliser qu’une seule Catégorie avec cette Zone ; si vous en voulez plusieurs, il vous suffit de développer le contenu de cette énumération.

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);

}

}

 

Cette méthode est l’une des deux plus importantes que nous implémentons ; c’est avec elle que nous écrivons réellement dans le journal ULS.  Sur la première ligne, j’indique la classe SPDiagnosticCategory et je fais référence à la Zone à laquelle elle appartient.  Sur la seconde ligne, j’appelle la méthode de cIasse de base sur la classe SPDiagnosticsServiceBase locale qui sera consignée dans le journal ULS et, dans ce contexte, je passe ma Catégorie qui est associée à ma Zone.

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;

}

 

Dans cette course, je renvoie à SharePoint l’ensemble de mes Zones personnalisées.  Dans ce cas, je vais juste utiliser ma Zone et c’est tout ce que je vais renvoyer.  De plus, comme je l’ai indiqué plus haut, j’utilise uniquement une Catégorie personnalisée avec ma Zone.  Si j’avais voulu utiliser plusieurs Catégories personnalisées, je les aurais 1) ajoutées à l’énumération décrite précédemment et 2) ajoutées une par une à l’instance de liste theCategories que j’ai définie dans cette méthode.

Ce qui est vraiment génial, c’est d’ajouter une Zone personnalisée et de la récupérer pour qu’elle s’affiche dans la colonne appropriée des journaux ULS.  L’implémentation de la classe de journalisation est également assez directe. Je vais coller la classe dans la partie principale du code, ici, et entrer un peu dans les détails pour expliquer :

    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);

            }

        }

    }

 

Ce code est ensuite assez simple à implémenter à partir de mes méthodes qui y font référence.  Puisque WriteLog est une méthode statique, mon code se limite à Log.WriteLog("This is my error message", TraceSeverity.Medium); par exemple.  Dans cet exemple, dans le journal ULS, une entrée est créée dans la Zone "Steve Area" et la Catégorie "SteveCategory" avec le message "This is my error message".

Ce billet de blog a été traduit de l’anglais. L’article d’origine est disponible à la page Tips for ULS Logging