Según la documentación de NLog:
La mayoría de las aplicaciones usarán un registrador por clase, donde el nombre del registrador es el mismo que el nombre de la clase.
Esta es la misma forma en que opera log4net. ¿Por qué es esta una buena práctica?
Respuestas:
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 un registrador para toda la aplicación, debe recurrir a más trucos de reflexión para saber de dónde provienen los mensajes de registro.
Compare lo siguiente:
Registro 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 necesitaría construir un seguimiento de pila para ver quién lo estaba llamando o su código siempre tendría que pasar a la persona que llama. Con el estilo de registrador por clase, aún lo hace, pero puede hacerlo una vez por clase en lugar de una vez por llamada y eliminar un problema de rendimiento grave.
fuente
Ventaja de usar "registrador por archivo" en NLog: tiene la posibilidad de administrar / filtrar registros por espacio de nombres 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
nlogger
fragmento creará el siguiente código:private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
Tan solo unas pocas pulsaciones de teclas y tienes registrador por clase. Utilizará el espacio de nombres y el nombre de la clase como nombre del registrador. Para establecer un nombre diferente a su registrador de clases, puede usar esto:
private static NLog.Logger logger = NLog.LogManager.GetLogger("MyLib.MyName");
Y, como dijo @JeremyWiebe, no tiene que usar 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 objetivo) mediante el uso
${logger}
en el diseño.fuente
Puedo ver algunas razones para esta elección.
fuente
También hay un beneficio de rendimiento en el caso de NLog. La mayoría de los usuarios usarán
Buscar la clase actual del seguimiento de la pila requiere algo de rendimiento (pero no mucho).
fuente
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 en el que este no es el mejor enfoque son los registros SQL de Hibernate. Hay un registrador compartido llamado "Hibernate.SQL" o algo por el estilo, donde varias clases diferentes escriben SQL sin formato en una sola categoría de registrador.
fuente
Desde el punto de vista del desarrollo, es más fácil si no tiene que crear un objeto de registro cada vez. Por otro lado, si no lo hace, sino que lo crea dinámicamente utilizando la reflexión, ralentizará el rendimiento. Para resolver esto, puede usar el siguiente código que crea el registrador de forma dinámica y asincrónica:
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); } } }
fuente
Inmediatamente me vienen a la mente dos razones:
fuente
Probablemente porque desea poder registrar métodos que solo son visibles para la clase sin romper la encapsulación, esto también facilita el uso de la clase en otra aplicación sin romper la funcionalidad de registro.
fuente
Facilita la configuración de appenders por espacio de nombres o clase.
fuente
Si está utilizando NLOG, puede especificar el sitio de llamadas en la configuración, esto registrará el nombre de la clase y el método donde se ubicó la declaración de registro.
<property name="CallSite" value="${callsite}" />
A continuación, puede utilizar una constante para el nombre de su registrador o el nombre del ensamblado.
Descargo de responsabilidad: no sé cómo NLOG recopila esta información, supongo que sería una 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.
fuente