Quiero usar un nlogger en mi aplicación, tal vez en el futuro necesite cambiar el sistema de registro. Entonces quiero usar una fachada de registro.
¿Conoce alguna recomendación de ejemplos existentes sobre cómo escribir esos? O simplemente dame un enlace a algunas de las mejores prácticas en esta área.
Respuestas:
Solía usar fachadas de registro como Common.Logging (incluso para ocultar mi propia biblioteca CuttingEdge.Logging ), pero hoy en día uso el patrón de Inyección de dependencia y esto me permite ocultar los registradores detrás de mi propia (simple) abstracción que se adhiere tanto a Dependency Principio de inversión y el principio de segregación de interfaces(ISP) porque tiene un miembro y porque mi aplicación define la interfaz; no una biblioteca externa. Minimizando el conocimiento que tienen las partes centrales de su aplicación sobre la existencia de bibliotecas externas, mejor; incluso si no tiene la intención de reemplazar su biblioteca de registro. La fuerte dependencia de la biblioteca externa hace que sea más difícil probar su código y complica su aplicación con una API que nunca fue diseñada específicamente para su aplicación.
Así es como suele verse la abstracción en mis aplicaciones:
Opcionalmente, esta abstracción se puede ampliar con algunos métodos de extensión simples (permitiendo que la interfaz se mantenga estrecha y siga adhiriéndose al ISP). Esto hace que el código para los consumidores de esta interfaz sea mucho más simple:
Dado que la interfaz contiene solo un método, puede crear fácilmente una
ILogger
implementación que sustituye al log4net , a Serilog , Microsoft.Extensions.Logging , Nlog o cualquier otra biblioteca de registro y configurar el contenedor de DI para inyectarlo en las clases que tienen unaILogger
en su constructor.Tenga en cuenta que tener métodos de extensión estáticos en la parte superior de una interfaz con un solo método es bastante diferente de tener una interfaz con muchos miembros. Los métodos de extensión son solo métodos auxiliares que crean un
LogEntry
mensaje y lo pasan a través del único método en laILogger
interfaz. Los métodos de extensión pasan a formar parte del código del consumidor; no forma parte de la abstracción. Esto no solo permite que los métodos de extensión evolucionen sin la necesidad de cambiar la abstracción, los métodos de extensión y laLogEntry
constructor siempre se ejecutan cuando se usa la abstracción del registrador, incluso cuando ese registrador es anulado / simulado. Esto brinda más certeza sobre la exactitud de las llamadas al registrador cuando se ejecuta en un conjunto de pruebas. La interfaz de un miembro también facilita las pruebas; Tener una abstracción con muchos miembros dificulta la creación de implementaciones (como simulacros, adaptadores y decoradores).Cuando hace esto, casi nunca hay necesidad de alguna abstracción estática que las fachadas de registro (o cualquier otra biblioteca) puedan ofrecer.
fuente
Usé el pequeño contenedor de interfaz + adaptador de https://github.com/uhaciogullari/NLog.Interface que también está disponible a través de NuGet :
fuente
A partir de ahora, la mejor opción es utilizar el paquete Microsoft.Extensions.Logging ( como señaló Julian ). La mayoría de los marcos de registro se pueden usar con esto.
Definir su propia interfaz, como se explica en la respuesta de Steven, está bien para casos simples, pero pasa por alto algunas cosas que considero importantes:
IsEnabled(LogLevel)
que desee, una vez más por motivos de rendimientoProbablemente puedas implementar todo esto en tu propia abstracción, pero en ese momento estarás reinventando la rueda.
fuente
Generalmente prefiero crear una interfaz como
y en el tiempo de ejecución inyecto una clase concreta que se implementa desde esta interfaz.
fuente
LogWarning
y losLogCritical
métodos y todos sus sobrecargas. Al hacer esto, violará el principio de segregación de interfaces . Prefiere definir laILogger
interfaz con un soloLog
método.LogEntry
, por tanto, una dependencia deLoggingEventType
. LaILogger
implementación debe lidiar con estosLoggingEventTypes
, probablementecase/switch
, lo cual es un olor a código . ¿Por qué esconder laLoggingEventTypes
dependencia? La implementación debe manejar los niveles de registro de todos modos , por lo que sería mejor explicar lo que debería hacer una implementación, en lugar de ocultarlo detrás de un método único con un argumento general.ICommand
que tiene unHandle
que toma unobject
. Las implementaciones debencase/switch
superar los tipos posibles para cumplir con el contrato de la interfaz. Esto no es ideal. No tenga una abstracción que oculte una dependencia que deba manejarse de todos modos. En su lugar, tenga una interfaz que indique claramente lo que se espera: "Espero que todos los registradores manejen Advertencias, Errores, Fatales, etc.". Esto es preferible a "Espero que todos los registradores manejen mensajes que incluyen Advertencias, Errores, Fatales, etc."LoggingEventType
debe llamarseLoggingEventLevel
como tipos son clases y debe codificarse como tal en OOP. Para mí, no hay diferencia entre no usar un método de interfaz y no usar elenum
valor correspondiente . En su lugarErrorLoggger : ILogger
, use ,InformationLogger : ILogger
donde cada registrador define su propio nivel. Luego, la DI necesita inyectar los registradores necesarios, probablemente a través de una clave (enumeración), pero esta clave ya no es parte de la interfaz. (Ahora eres SÓLIDO).Una gran solución a este problema ha surgido en forma del proyecto LibLog .
LibLog es una abstracción de registro con soporte incorporado para los principales registradores, incluidos Serilog, NLog, Log4net y Enterprise logger. Se instala a través del administrador de paquetes NuGet en una biblioteca de destino como un archivo de origen (.cs) en lugar de una referencia .dll. Ese enfoque permite que se incluya la abstracción del registro sin obligar a la biblioteca a asumir una dependencia externa. También permite al autor de una biblioteca incluir el registro sin forzar a la aplicación consumidora a proporcionar explícitamente un registrador a la biblioteca. LibLog usa la reflexión para averiguar qué registrador de concreto está en uso y conectarse a él sin ningún código de cableado explícito en los proyectos de la biblioteca.
Por lo tanto, LibLog es una gran solución para iniciar sesión en proyectos de biblioteca. ¡Simplemente haga referencia y configure un registrador de concreto (Serilog para ganar) en su aplicación o servicio principal y agregue LibLog a sus bibliotecas!
fuente
En lugar de escribir su propia fachada, puede utilizar Castle Logging Services o Simple Logging Façade .
Ambos incluyen adaptadores para NLog y Log4net.
fuente
Desde 2015, también puede usar .NET Core Logging si está creando aplicaciones .NET core.
El paquete para que NLog se conecte es:
fuente