2010-06-29 5 views
77

De acuerdo con la documentación del Nlog:¿Por qué los madereros recomiendan usar un registrador por clase?

mayoría de las aplicaciones utilizar uno registrador por clase, donde el nombre del registrador es el mismo que el nombre de la clase.

Esta es la misma manera que funciona log4net. ¿Por qué es esta una buena práctica?

+1

hmm. parece que hay dos problemas aquí: uno tiene un objeto de registro real por clase y el otro tiene el nombre del registro igual a la clase. –

Respuesta

49

Con log4net, el uso de un registrador por clase facilita la captura de la fuente del mensaje de registro (es decir, la clase que escribe en el registro). Si no tiene un registrador por clase, sino que tiene un registrador para toda la aplicación, necesita recurrir a más trucos de reflexión para saber de dónde provienen los mensajes de registro.

Compare los siguientes:

Entrar por clase

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

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

Un registrador por aplicación (o similar)

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

-- or -- 

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

Usando el segundo ejemplo, el registrador tendría que construir una pila trace para ver quién lo llama o su código siempre tendrá que pasar a la persona que llama. Con el estilo de logger por clase, aún lo hace, pero puede hacerlo una vez por clase en lugar de una vez por llamada y eliminar un problema grave de rendimiento.

+0

Gracias, eso ayuda a aclarar las cosas. Simplemente colocamos manualmente el nombre y el método de la clase en el mensaje (es decir, "ImageCreator.CreateThumbnail() called"), pero es mejor si el registrador puede manejarlo. –

+1

Solo para su información, se ha convertido en una práctica "mejor" tener un registrador por instancia, en lugar de por clase (es decir, estático) porque eso facilita la captura de información, como la información de la secuencia. Obviamente es una cuestión de gusto, no hay una "regla dura y rápida", pero quería descartarlo. –

+6

@will, ¿puedes explicar eso un poco más? Al iniciar sesión usando un registrador por clase, siempre registro la identificación del hilo para que el registrador pueda obtener la información actual del hilo. Cualquier otra información de hilo estaría disponible para el registrador también. –

0

Probablemente porque desea poder registrar métodos que solo son visibles para la clase sin romper la encapsulación, esto también hace que sea fácil usar la clase en otra aplicación sin romper la funcionalidad de registro.

+0

Hace que sea difícil usar esa clase en otra aplicación. Debe hacer referencia a la biblioteca de registro, le guste o no. –

1

dos razones inmediatamente vienen a la mente:

  1. Tener un registro separado para cada clase hace que sea fácil para agrupar todos los mensajes de registro/errores que pertenecen a una clase dada.
  2. Tener un registro dentro de una clase le permite registrar detalles internos que pueden no ser accesibles fuera de la clase (por ejemplo, estado privado, información relacionada con la implementación de una clase, etc.).
+1

Tiene un registrador en la clase, independientemente de si está definido a nivel de clase o globalmente. Los registradores globales no están "fuera" de la clase desde una perspectiva de visibilidad. Todavía hace referencia al registrador global desde * dentro * de la clase en cuestión para que tenga visibilidad completa. – Robert

5

Puedo ver algunas razones para esta elección.

  • Siempre sabrá de dónde vino una declaración de registro en particular, si incluye el nombre del registrador en el formato de salida de su registro.
  • Puede controlar qué declaraciones de registro ve en un nivel de grano fino activando o desactivando ciertos registradores, o estableciendo su nivel.
3

En la mayoría de los casos, el nombre de la clase proporciona un buen nombre para el registrador. Al escanear los archivos de registro, puede ver el mensaje de registro y asociarlo directamente con una línea de código.

Un buen ejemplo donde este no es el mejor enfoque, son los registros SQL de Hibernate. Hay un registrador compartido llamado "Hibernate.SQL" o algo así, donde varias clases diferentes escriben SQL sin formato en una única categoría de registrador.

0

Facilita la configuración de los appenders por espacio de nombres o clase.

11

Ventaja para usar "logger por archivo" en NLog: tiene la posibilidad de administrar/filtrar registros por nombre y nombre de clase. Ejemplo:

<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 tiene un fragmento de código muy útil para hacer esto. El fragmento nlogger creará el siguiente código:

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

Así sólo pulsar unas teclas y tiene registrador por clase. Utilizará el espacio de nombres y el nombre de clase como el nombre del registrador. Para establecer el nombre diferente a su registrador de clase, puede utilizar esto:

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

Y, como dijo @JeremyWiebe, usted no tiene que utilizar trucos para obtener el nombre de la clase que está tratando de registrar un mensaje : El nombre del registrador (que generalmente es el nombre de la clase) puede registrarse fácilmente en el archivo (u otro destino) mediante el uso de ${logger} en el diseño.

0

También hay un beneficio de rendimiento en el caso de NLog. La mayoría de los usuarios usarán

Logger logger = LogManager.GetCurrentClassLogger() 

Buscando la clase actual del rastro de la pila toma algo (pero no mucho) el rendimiento.

0

Desde el punto de vista del desarrollo, es más fácil si no tiene que crear un objeto logger cada vez. Por otro lado, si no lo haces, sino que lo creas dinámicamente mediante la reflexión, se ralentizará el rendimiento. Para solucionar esto, puede utilizar el siguiente código que crea el registrador dinámicamente de forma asíncrona:

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

     } 
    } 
} 
0

Si está utilizando Nlog puede especificar la callsite en la configuración, esto va a registrar el nombre de la clase y el método en que la declaración de registro Está localizado.

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

Podría utilizar una constante para su nombre de registrador o el nombre del ensamblado.

Descargo de responsabilidad: No sé cómo NLOG recopila esta información, supongo que sería reflexión, por lo que es posible que deba considerar el rendimiento. Hay algunos problemas con los métodos Async si no está utilizando NLOG v4.4 o posterior.

Cuestiones relacionadas