Este es un enfoque interesante, sin embargo, parece adolecer del inconveniente de que todos los registradores que se inyectan (o el único singleton que se inyecta) serán la misma instancia (o tendrán el mismo nombre, siendo el nombre el nombre de la clase NLogLoggingService. Eso significa que no puede controlar fácilmente la granularidad del registro (es decir, activar el registro en el nivel "Información" en una clase y "Advertir" en otra clase). También, si opta por utilizar el sitio de llamada formateo de fichas, siempre obtendrá el sitio llamado de la llamada, el registrador Nlog en lugar del sitio de llamadas en el código de aplicación
Aquí es una versión abreviada del registrador que se vinculó:.
[Export(Services.Logging.LoggingService, typeof(ILoggingService))]
class NLogLoggingService : ILoggingService
{
Logger log; public NLogLoggingService()
{
log = LogManager.GetCurrentClassLogger();
}
public void Debug(object message)
{
log.Debug(message);
}
public void DebugWithFormat(string format, params object[] args)
{
if (args.Length == 0)
{
log.Debug(format);
}
else
{
Debug(string.Format(format, args));
}
}
public bool IsDebugEnabled
{
get
{
return log.IsDebugEnabled;
}
}
}
En el constructor LogManager.GetCurrentClassLogger()
se utiliza para obtener el registrador NLog. GetCurrentClassLogger devolverá un registrador NLog que está "nombrado" basado en el tipo "actual", que, en este caso, es NLogLoggingService. Entonces, para configurar NLog en el archivo app.config, se configurará en función de que el registrador se llame "SoapBox.Core.NLogLoggingService". Comúnmente, en el código que utiliza Nlog (o log4net) directamente, cada clase tiene su propio nombre único registrador de la siguiente manera:
namespace MyNamespace
{
public class MyClass1
{
private static readonly Logger logger LogManager.GetCurrentClassLogger();
public void DoSomeWork()
{
logger.Info("Logging from inside MyClass1.DoSomeWork");
}
}
public class MyClass2
{
private static readonly Logger logger LogManager.GetCurrentClassLogger();
public void DoSomeWork()
{
logger.Info("Logging from inside MyClass2.DoSomeWork");
}
}
}
Ahora el registro para MyClass1 y miclase2 es regulable. Puedes configurar diferentes niveles para cada clase, enviarlos a diferentes objetivos o desactivarlos por completo. Alternativamente, debido al concepto de jerarquías de registrador en log4net y NLog, puede controlar el registro en ambas clases simultáneamente configurando un "registrador" para el espacio de nombres (MyNamespace en este caso), o cualquier espacio de nombres "ancestro". Si no hay un registrador configurado para el nombre de tipo completamente calificado, entonces el marco de registro esencialmente sube la jerarquía considerando el nombre una cadena delimitada por puntos y eliminando el último fragmento y comprobando si ese registrador está configurado. Entonces, en este caso, estamos solicitando registradores para MyNamespace.MyClass1 y MyNamespace.MyClass2.Podría configurar el archivo app.config para que MyNamespace inicie sesión en la "información" y escriba en un destino de archivo (appender en log4net-speak). Si lo hice, los dos registradores que solicité a través de sus nombres completos heredarán la configuración de MyNamespace.
Con la forma sugerida de inyectar NLog a través de MEF, solo tendrá una instancia de registrador, por lo que no puede configurar cada clase para que se registre de manera diferente. Además, como mencioné anteriormente, si opta por registrar la información del sitio de llamadas, siempre obtendrá "SoapBox.Core.NLogLoggingService" para la clase y "Debug" (o DebugWithFormat, o Info, o InfoWithFormat, etc.) para el método.
Esto parece ser un problema al inyectar con éxito los registradores de log4net y NLog. Puedes ver el question que pregunté sobre este mismo problema hace un par de meses.
Al final pude averiguar cómo algunos marcos de inyección de dependencia pueden inyectar log4net y NLog loggers que son específicos de la clase que se está creando (es decir, si el marco DI crea una instancia de MyClass, que a su vez depende de una interfaz de ILogger, entonces MyClass obtendrá un registrador que es esencialmente equivalente a lo que hubiera sucedido si MyClass solicitara el logger a través de LogManager.GetCurrentClassLogger api). En general, los "resolvers" en los marcos DI/IoC reciben el contexto actual (que contiene, entre otra información, el tipo de objeto que se está creando actualmente). Con ese tipo disponible, se convierte en una simple cuestión de tener un resolvedor específico de un framework de registro que reciba ese tipo y pasarlo junto al marco de registro para crear un logger apropiado para ese tipo.
Para aprovechar al máximo las capacidades de NLog (y log4net), realmente le gustaría poder decirle a MEF que su clase es dependiente de "ILogger", pero también que la instancia de "ILogger" que se inyecta en tu clase debe depender del tipo de tu clase.
No sé qué tan fácil será lograr eso con MEF. Alternativamente, podría ajustar el LogManager estático de NLog en un ILogManager e inyectarlo. Eso se desviaría del paradigma "inyectar ILogger" normal.
En resumen: si se inyecta NLog a través de MEF de esta manera, de hecho podrá iniciar sesión con NLog, pero solo tendrá un registrador con nombre (SoapBox.Core.NLogLoggingService). Esto significa que no podrá controlar con ningún grado de granularidad, ya sea para niveles/encendido/apagado o para salida (NLog Target/log4net Appender)
No tengo una buena respuesta para qué hacer en la medida de lo posible como inyectar NLog a través de MEF Y manteniendo la granularidad/flexibilidad que le da NLog "en bruto".
Puedo decir que hemos decidido usar Common.Logging for .NET para abstraer el marco de trabajo pero decidimos NO inyectar el registro. En su lugar, solo usaremos un LogManager estático (como lo proporciona Common.Logging) para entregar los registradores.
Esa es una buena aplicación de un registrador NLog capaz de MEF, pero adolece de un par de inconvenientes: 1. Todos los registradores MEF-ed para una aplicación serán en realidad el mismo registrador, por lo que no tiene mucho control sobre su registro. 2. La información del sitio de llamada se pierde porque se utilizará el sitio de llamada de la clase de registro. Por la parte superior de mi cabeza no tengo una mejor sugerencia para MEF, pero creo que vale la pena señalar esas deficiencias. Ver mi respuesta para una versión más larga. – wageoghe