Estoy tratando de averiguar cuál es el patrón y el uso correctos de log4net con un marco de inyección de dependencia.
Log4Net usa la interfaz ILog pero requiere que llame
LogManager.GetLogger(Reflection.MethodBase.GetCurrentMethod().DeclaringType)
en cada clase o método donde necesito registrar información. Esto parece ir en contra de los principios de IoC y me une al uso de Log4Net.
¿Debería de alguna manera poner otra capa de abstracción en alguna parte?
Además, necesito registrar propiedades personalizadas como el nombre de usuario actual como este:
log4net.ThreadContext.Properties["userName"] = ApplicationCache.CurrentUserName;
¿Cómo puedo encapsular esto para que no tenga que recordar hacerlo cada vez y aún así mantener el método actual que está registrando? ¿Debo hacer algo como esto o me estoy equivocando totalmente?
public static class Logger
{
public static void LogException(Type declaringType, string message, Exception ex)
{
log4net.ThreadContext.Properties["userName"] = ApplicationCache.CurrentUserName;
ILog log = LogManager.GetLogger(declaringType);
log.Error(message, ex);
}
}
Respuestas:
Creo que aquí no estás viendo el bosque por los árboles. ILog y LogManager son una fachada liviana equivalente a casi 1: 1 de Apache commons-logging, y en realidad no acoplan su código al resto de log4net.
<rant>
También descubrí que casi siempre cuando alguien crea un contenedor MyCompanyLogger alrededor de log4net, pierde el punto y pierde capacidades importantes y útiles del marco, desecha información útil, pierde las ganancias de rendimiento posibles usando incluso la interfaz ILog simplificada, O todo lo anterior. En otras palabras, envolver log4net para evitar el acoplamiento es un anti-patrón .
</rant>
Si siente la necesidad de inyectarlo, haga que su instancia de registrador sea accesible a través de una propiedad para habilitar la inyección, pero cree una instancia predeterminada a la antigua.
En cuanto a incluir el estado contextual en cada mensaje de registro, debe agregar una propiedad global cuya
ToString()
resolución sea lo que está buscando. Como ejemplo, para el tamaño de pila actual:Luego, para enchufarlo durante el inicio:
fuente
Lo que hice fue crear mi propia interfaz e hice que una clase implementara esa interfaz que usaba Log4Net e inyectara esa clase. De esa manera, no está atado a Log4Net ... puede simplemente crear otra clase para un nuevo registrador e inyectar esa clase.
fuente
Si está realmente preocupado por tener varios registradores, siempre puede declarar un registrador global y llamarlo para todas sus necesidades de registro. La desventaja de esto es que pierde la capacidad incorporada para identificar la clase desde la que se emitió el registro, pero también puede inyectar su propio mensaje personalizado en el registro para identificar la clase.
Depende de lo robusto que desee que sea el registro. También puede simplemente poner el registrador en la clase principal y dejar que todas las excepciones no manejadas aparezcan para el registro.
fuente
Otra forma de hacerlo sería conectar la secuencia de registro del contenedor de la interfaz log4net ILog como esta: (usando Castle en un contexto ASP.NET a continuación como ejemplo)
y simplemente inyecte el constructor ILog siempre que lo necesite.
fuente
Component.For<ILog>().UsingFactoryMethod((kernel, model, cc) => LogManager.GetLogger(cc.Handler.ComponentModel.Implementation))