c# - logmanager - log4net vb net
Usando Ninject para llenar la dependencia de Log4Net (7)
El alcance de ILog
e ILogger
debe ser Transitorio, de lo contrario, solo reutilizará el primer registrador que cree. Gracias a @Meryln Morgan-Graham por ayudarme a encontrar eso.
Uso Ninject como contenedor DI en mi aplicación. Para acoplar libremente a mi biblioteca de registro, uso una interfaz como esta:
public interface ILogger
{
void Debug(string message);
void Debug(string message, Exception exception);
void Debug(Exception exception);
void Info(string message);
...you get the idea
Y mi implementación se ve así.
public class Log4NetLogger : ILogger
{
private ILog _log;
public Log4NetLogger(ILog log)
{
_log = log;
}
public void Debug(string message)
{
_log.Debug(message);
}
... etc etc
Una clase de muestra con una dependencia de registro
public partial class HomeController
{
private ILogger _logger;
public HomeController(ILogger logger)
{
_logger = logger;
}
Al crear una instancia de Log4Net, debe asignarle el nombre de la clase para la que se registrará. Esto está demostrando ser un desafío con Ninject.
El objetivo es que al crear una instancia de HomeController, Ninject debe crear una instancia de ILog con un "nombre" de "HomeController"
Esto es lo que tengo para config.
public class LoggingModule : NinjectModule
{
public override void Load()
{
Bind<ILog>().ToMethod(x => LogManager.GetLogger(GetParentTypeName(x)))
.InSingletonScope();
Bind<ILogger>().To<Log4NetLogger>()
.InSingletonScope();
}
private string GetParentTypeName(IContext context)
{
return context.Request.ParentContext.Request.ParentContext.Request.Service.FullName;
}
}
Sin embargo, el "Nombre" que se pasa a ILog no es lo que estoy esperando. No puedo entender ninguna rima o razón, a veces está bien, la mayoría de las veces no lo es. Los nombres que estoy viendo son nombres de OTRAS clases que también tienen dependencias en el ILogger.
La extensión Ninject.Extension.Logging ya proporciona todo lo que estás implementando. Incluye soporte para log4net, NLog y NLog2.
https://github.com/ninject/ninject.extensions.logging
También desea utilizar lo siguiente como tipo de registrador:
context.Request.ParentRequest.ParentRequest.Target.Member.DeclaringType
De lo contrario, obtendrá el registrador para el tipo de servicio en lugar del tipo de implementación.
Me gusta la idea de envolver Log4Net en mis propias interfaces. No quiero depender de la implementación de Ninjects, porque para mí eso solo significa que tomo una dependencia de Ninject en toda mi aplicación y pensé que era exactamente lo contrario de lo que es la inyección de dependencia. Desacoplamiento de servicios de terceros. Así que tomé el código de carteles original, pero cambié el siguiente código para que funcione.
private string GetParentTypeName(IContext context)
{
var res = context.Request.ParentRequest.ParentRequest.Service.FullName;
return res.ToString();
}
Tengo que llamar a ParentRequest.ParentRequest para que cuando imprima el layout% logger imprima la clase que llama al método Log4Net log en lugar de la clase Log4Net del método que llamó al método Log.
Para todos los que todavía están buscando la respuesta correcta, la implementación correcta es:
public class LoggingModule : NinjectModule
{
public override void Load()
{
Bind<ILog>().ToMethod(x => LogManager.GetLogger(x.Request.Target.Member.DeclaringType));
Bind<ILogger>().To<Log4NetLogger>()
.InSingletonScope();
}
}
Enfásis en:
x.Request.Target.Member.DeclaringType
Personalmente, no tengo ningún interés en abstraer mi registrador, por lo que mis módulos de implementación hacen referencia a log4net.dll
directamente y mis constructores solicitan un ILog
como desee.
Para lograr esto, un registro de una línea que usa Ninject v3 se ve así al final de mis Servicios de static void RegisterServices( IKernel kernel )
:
kernel.Bind<ILog>().ToMethod( context=>
LogManager.GetLogger( context.Request.Target.Member.ReflectedType ) );
kernel.Get<LogCanary>();
}
class LogCanary
{
public LogCanary(ILog log)
{
log.Debug( "Debug Logging Canary message" );
log.Info( "Logging Canary message" );
}
}
Para facilitar el diagnóstico de los problemas de registro, al principio también me pego lo siguiente para recibir un mensaje no dirigido por DI:
public static class NinjectWebCommon
{
public static void Start()
{
LogManager.GetLogger( typeof( NinjectWebCommon ) ).Info( "Start" );
Lo que da lugar a lo siguiente en el inicio de la aplicación:
<datetime> INFO MeApp.App_Start.NinjectWebCommon - Start
<datetime> DEBUG MeApp.App_Start.NinjectWebCommon+LogCanary - Debug Logging Canary message
<datetime> INFO MeApp.App_Start.NinjectWebCommon+LogCanary - Logging Canary message
tal vez mi respuesta sea tarde pero estoy usando este formato:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ILog>()
.ToMethod(c => LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType))
.InSingletonScope();
}
Bind<ILog>().ToMethod(x => LogManager.GetLogger(GetParentTypeName(x)))
.InSingletonScope();
Actualmente está enlazando en el ámbito Singleton , por lo que solo se crea un registrador que usará el nombre del primero creado. En su lugar usa InTransientScope()