web-dev-qa-db-fra.com

Pourquoi les enregistreurs recommandent-ils d'utiliser un enregistreur par classe?

Selon la documentation de NLog:

La plupart des applications utilisent un enregistreur par classe, son nom étant identique à celui de la classe.

C'est la même manière que log4net fonctionne. Pourquoi est-ce une bonne pratique?

80
Daniel T.

Avec log4net, l’utilisation d’un journal par classe facilite la capture de la source du message de journal (c’est-à-dire la classe qui écrit dans le journal). Si vous n'avez pas un enregistreur par classe, mais plutôt un enregistreur pour l'application entière, vous devez recourir à davantage d'astuces de réflexion pour savoir d'où proviennent les messages de journalisation. 

Comparez ce qui suit:

Journal par classe

using System.Reflection;
private static readonly ILog _logger = 
    LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);    

public void SomeMethod()
{
    _logger.DebugFormat("File not found: {0}", _filename);
}

Un enregistreur par application (ou similaire)

Logger.DebugFormat("File not found: {0}", _filename); // Logger determines caller

-- or --

Logger.DebugFormat(this, "File not found: {0}", _filename); // Pass in the caller

En utilisant le deuxième exemple, le Logger devrait créer une trace de pile pour voir qui l’appelait ou votre code devrait toujours transmettre l’appelant. Avec le style enregistreur par classe, vous le faites toujours, mais vous pouvez le faire une fois par classe au lieu d'une fois par appel, ce qui élimine un grave problème de performances.

53
Jeremy Wiebe

Avantage d'utiliser "enregistreur par fichier" dans NLog: vous avez la possibilité de gérer/filtrer les journaux par espace de noms et nom de classe. Exemple:

<logger name="A.NameSpace.MyClass"      minlevel="Debug" writeTo="ImportantLogs" /> 
<logger name="A.NameSpace.MyOtherClass" minlevel="Trace" writeTo="ImportantLogs" /> 
<logger name="StupidLibrary.*"          minlevel="Error" writeTo="StupidLibraryLogs" />

<!-- Hide other messages from StupidLibrary -->
<logger name="StupidLibrary.*" final="true" /> 

<!-- Log all but hidden messages -->
<logger name="*" writeTo="AllLogs" /> 

NLogger a un extrait de code très utile pour le faire. L'extrait nlogger créera le code suivant:

private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

Donc, seulement quelques frappes et vous avez un enregistreur par classe. Il utilisera l’espace de noms et le nom de la classe comme nom de l’enregistreur. Pour définir un nom différent pour votre enregistreur de classe, vous pouvez utiliser ceci:

private static NLog.Logger logger = NLog.LogManager.GetLogger("MyLib.MyName");

Et, comme @JeremyWiebe l'a dit, vous n'avez pas besoin d'utiliser des astuces pour obtenir le nom de la classe qui tente de consigner un message: le nom de l'enregistreur (qui est généralement le nom de la classe) peut être facilement enregistré (ou une autre cible) en utilisant ${logger} dans la présentation.

14
CoperNick

Je peux voir quelques raisons pour ce choix.

  • Vous saurez toujours d'où provient une instruction de journal particulière, si vous incluez le nom de l'enregistreur dans le format de sortie de votre journal.
  • Vous pouvez contrôler les instructions de journal que vous voyez à un niveau de grain fin en activant ou désactivant certains enregistreurs ou en définissant leur niveau.
5
Peter Recore

Dans la plupart des cas, le nom de la classe fournit un bon nom pour le consignateur. Lors de l'analyse des fichiers journaux, vous pouvez voir le message de journal et l'associer directement à une ligne de code.

Les journaux SQL d'Hibernate constituent un bon exemple de ce qui n'est pas la meilleure approche. Il existe un enregistreur partagé nommé "Hibernate.SQL" ou quelque chose du genre, dans lequel un certain nombre de classes différentes écrivent du SQL brut dans une seule catégorie d'enregistreur.

3
Eric Hauser

Il existe également un avantage de performance dans le cas de NLog. La plupart des utilisateurs vont utiliser 

Logger logger = LogManager.GetCurrentClassLogger()

La recherche de la classe actuelle à partir de la trace de pile nécessite certaines performances (mais pas beaucoup). 

2
Julian

Du point de vue du développement, il est plus facile de ne pas créer d’objet enregistreur à chaque fois. Par contre, si vous ne le faites pas, mais si vous le créez de manière dynamique en utilisant la réflexion, cela ralentira les performances. Pour résoudre ce problème, vous pouvez utiliser le code suivant qui crée le journal de façon dynamique de manière asynchrone:

using NLog;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WinForms
{
    class log
    {

        public static async void Log(int severity, string message)
        {
            await Task.Run(() => LogIt(severity, message));
        }

        private static void LogIt(int severity, string message)
        {
            StackTrace st = new StackTrace();
            StackFrame x = st.GetFrame(2);     //the third one goes back to the original caller
            Type t = x.GetMethod().DeclaringType;
            Logger theLogger = LogManager.GetLogger(t.FullName);

            //https://github.com/NLog/NLog/wiki/Log-levels
            string[] levels = { "Off", "Trace", "Debug", "Info", "Warn", "Error", "Fatal" };
            int level = Math.Min(levels.Length, severity);
            theLogger.Log(LogLevel.FromOrdinal(level), message);

        }
    }
}
2
as9876

Deux raisons viennent immédiatement à l’esprit:

  1. Avoir un journal séparé pour chaque classe facilite le regroupement de tous les messages/erreurs de journal relatifs à une classe donnée.
  2. Avoir un journal dans une classe vous permet de consigner des détails internes qui peuvent ne pas être accessibles en dehors de la classe (par exemple, un état privé, des informations relatives à la mise en œuvre d'une classe, etc.).
1
Dan Tao

Probablement parce que vous voulez pouvoir journaliser des méthodes qui ne sont visibles que par la classe sans rompre l'encapsulation, cela facilite également l'utilisation de la classe dans une autre application sans interrompre la fonctionnalité de journalisation.

0
Rodrick Chapman

Facilite la configuration des ajouts par espace de noms ou classe.

0
dotjoe

Si vous utilisez NLOG, vous pouvez spécifier le site d’appel dans la configuration. Ceci enregistrera le nom de la classe et la méthode où l’instruction de consignation a été localisée.

<property name="CallSite" value="${callsite}" />

Vous pouvez ensuite utiliser une constante pour le nom de votre enregistreur ou le nom de l’assemblage.

Clause de non-responsabilité: je ne sais pas comment NLOG collecte ces informations, je suppose que ce serait une réflexion afin que vous puissiez avoir besoin de prendre en compte la performance. Il existe quelques problèmes avec les méthodes asynchrones si vous n'utilisez pas NLOG version 4.4 ou ultérieure.

0
user6271979