2009-11-11 6 views
13

Tengo una solución que consiste en una aplicación principal de winforms, con DLL de biblioteca de clases internamente asociadas desde las cuales deseo iniciar sesión. Este registro debe ser realizado por el mismo registrador, independientemente de si el cliente de UI principal o el dll asociado lo llama. El dll puede, por supuesto, ser utilizado por otras aplicaciones que tienen diferentes registradores en otras soluciones, pero en estas circunstancias tendrá una configuración log4net diferente y tal vez un conjunto diferente de complementos en total.¿Cuál es el mejor patrón para usar el mismo registrador Log4net en muchos ensambles en una solución?

Un enfoque sería crear un singleton dentro de la aplicación principal y el registro de eso, sin embargo desde log4net es su propio singleton, que se puede referenciar siempre que pasemos la misma cadena (o tipo) a log4net.LogManager.GetLogger lo haremos iniciar sesión en el mismo destino (en mi caso, deseo utilizar un RollingFileAppender).

Esto funciona. Sin embargo, dado que el DLL tendrá varias clases, significaría que cada instancia de clase o clase estática a partir de la cual deseamos iniciar sesión requeriría i) un argumento que defina el nombre del registrador (para iniciar sesión en el mismo destino) y ii) en cada punto de entrada necesitaría llamar al log4net.LogManager.GetLogger(loggerName).

¿Cuál es el mejor patrón para usar aquí? ¿El enfoque correcto sería crear una instancia única en cada ensamblado? Mi preocupación aquí es que todavía tendremos que pasar el nombre del registrador a cada punto de entrada para el dll, lo que parece exagerado. Para evitar pasar el nombre del registrador, podría suponer que siempre es igual a System.Reflection.Assembly.GetCallingAssembly().GetName().Name.

Si esto es demasiado difícil para log4net, ¿hay otras soluciones más sencillas, como Enterprise Logging Block? ¿O es la mejor solución un enfoque de programación orientada a aspectos (AOP)?

Reference for anti-pattern approach for singleton here.

Respuesta

16

Casi un año después, pero yo pensaba que iba a contribuir de todos modos!

Basado en su comentario al post de Carl, creo que tal vez usted no entiende cómo funciona log4net. Sí, el loggername identifica el registrador. Sí, un registrador puede tener muchos apéndices. PERO, muchos registradores también pueden escribir en el MISMO appender. Por lo tanto, podría configurar los registradores "A", "B" y "C" a todos los registros en el archivo "X". Usted puede obtener los registradores de la siguiente manera:

ILog logger_a = LogManager.GetLogger("A"); 
ILog logger_b = LogManager.GetLogger("B"); 
ILog logger_c = LogManager.GetLogger("C"); 

Ahora, si inicia sesión con cualquiera de estos registradores, todos ellos pueden ir al mismo lugar (archivo "X") si se ha configurado de esa manera.

La ventaja de no usar el mismo nombre registrador a través de su aplicación es que se puede controlar el nivel de registro en diferentes lugares de su aplicación a través del archivo de configuración. Entonces, si el código que está utilizando los registradores "A" y "B" está funcionando bien, pero el código que está utilizando el registrador "C" está teniendo un problema, puede desactivar "A" y "B" y girar " C "todo el camino hacia arriba". De esta forma, tendrá menos información para buscar su problema.

mayoría de las personas (o al menos la mayoría de los ejemplos log4net) crean en realidad una instancia registrador estático por clase, el nombre de la clase (que no recuerdo la sintaxis exacta, pero es fácil encontrar ejemplos). Esto le proporciona un nivel muy alto de granularidad para controlar su registro.

En su archivo app.config, puede controlar todos los registradores en el mismo nivel configurando un solo registrador llamado "*" o puede configurar registradores específicos (usando el nombre de tipo completo) o incluso puede configurar por partes del nombre de tipo completamente calificado. Por ejemplo, se puede hacer muy fácilmente en todas las clases del espacio de nombres del registro ABC a nivel de "información", en todas las clases de registro DEF espacio de nombres en el nivel "error", y todas las clases de espacio de nombres de GHI no inician sesión en absoluto. Y todos estos registradores pueden iniciar sesión en el mismo destino (por ejemplo, archivo X).

podría haber sido demasiado tarde para ayudar, pero tal vez no ...

+0

En mi pregunta original, decidí que gran parte de lo que deseaba registrar era en realidad retroalimentación de progreso, así que publiqué los eventos consumidos por la aplicación principal, pero su explicación aquí es de lejos la más clara, y también la he usado en otros lugares. – Topdown

+0

Estoy leyendo esto 6 años después, así que no, ¡nunca demasiado tarde! :-) – nashwan

1

Supongo que podría tener el loggerName en su app.config.

¿Puedo preguntar por qué loggerName tiene que ser el mismo para toda la aplicación?

+0

Según tengo entendido, el nombre del registrador es el identificador de un registrador. Donde un registrador puede tener muchos apéndices.Entonces, si quiero usar los mismos anexos y en el caso de RollingFileAppender iniciar sesión en el mismo archivo de dll, entonces necesito el mismo nombre de registrador para cada llamada a GetLogger. ¿O lo he entendido mal? – Topdown

+0

@Topdown: has malentendido. Debe familiarizarse con http://logging.apache.org/log4net/release/faq.html –

0

Seguimos un enfoque para usar log4net similar a esto.

Usamos log4net tanto en la aplicación principal como en los conjuntos de bibliotecas de clases. Escribimos una clase contenedora alrededor, para que todo el registro aparezca con el mismo tipo de configuración de donde lo llamemos y también para asegurarse de que sea un singleton. Esta clase contenedora se llama desde cualquier lugar dentro de nuestra aplicación.

Como resultado, las bibliotecas de clase y la aplicación principal cierran sesión en el mismo archivo de registro con la misma configuración, que es lo que queríamos. ¿Es esto lo que estabas tratando de lograr?

3

Primero, debe crear una clase contenedora (para desacoplar su aplicación del proveedor de registro).

Esta clase contenedora podría tomar el identificador del registrador. Si está utilizando un contenedor IoC, puede simplemente insertar el nombre del registrador o una instancia preconfigurada existente.

Si está utilizando la unidad (otros recipientes son similares), usted podría hacer algo como

// During application initialization 
IUnityContainer myContainer = new UnityContainer(); 
LoggingService concreteLoggingService = new LoggingService("logID"); 
myContainer.RegisterInstance<ILoggingService>(concreteLoggingService); 

// This would be injected, so you wouldn't see this, but it's here for consistency 
ILoggingService loggingService = myContainer.Resolve<ILoggingService>(); 
loggingService.LogMessage("message"); 

Ahora bien, esto supone que tiene un contenedor IoC.También puede crear un localizador de servicio:

// During application initialization 
ServiceLocator.Register<ILoggingService>(new LoggingService("logID")); 

// Retrieved as needed 
ILoggingService loggingServce = LoggingServiceLocator.Locate<ILoggingService>(); 
loggingService.LogMessage("message"); 

En el segundo caso, debe escribir todo el código de plomería. Con un contenedor IoC, lo obtienes de fábrica.

+0

¿Por qué? No recomendaría este enfoque. Para "desacoplar" el marco de trabajo de registro del proveedor es inyectar otra capa de indirección sin obtener nada de valor. El patrón de uso de log4net es simple de codificar y es simple de reemplazar. Envolverlo en una capa adicional de indirección no le da ningún valor y es una solución teórica para un problema. –

+1

@Casper, creo que la abstracción es útil para permitir la burla durante las pruebas unitarias. –

+0

Entiendo las palabras que utiliza, pero lo que usted describe es, en mi opinión, un malentendido sobre la naturaleza de su registrador. ¿Por qué habría de abstraer innecesariamente algo que le proporciona un código de producción adicional, más puntos de falla de producción y nada de valor, solo para satisfacer algún requisito acumulado de "abstraer todo en la prueba de unidad". Log4Net en sí mismo ya está abstraído de tal manera que no influye - ni lo hará nunca - en las pruebas de su unidad. –

0

¿Qué hay de la implementación de su propia TraceListener para que sólo se puede utilizar Trace.Write a través de su aplicación?

+0

¿Cómo está relacionado esto con la pregunta? –

+0

@CasperLeonNielsen Implementa un TraceListener personalizado (que es parte de .NET) que escribe en el registro usando Log4net. Añádalo a la colección Listeners (parte de .NET) al inicio, luego en cualquier dll o clase o lo que quiera, use Trace.Write (parte de .NET) y termine en su archivo de registro Log4net. –

+0

Permítanme reformular eso: eso no está conectado a la pregunta. Lo que está proponiendo es una forma de evadir el escenario de uso normal de log4net, sin obtener nada más que una mayor complejidad. –

0

nunca he visto a otro, patrón significativo, el uso de esto para log4net:

En la parte superior de cualquier clase que necesita registro, hacer:

private static ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 

En los AssemblyInfo.cs capas de acogida, hacer:

[assembly: log4net.Config.XmlConfigurator] 

En el inicio del host, realice la configuración programática de los appenders, etc., o use la configuración simple de app.config.

Fin de la historia. Sin envoltorios. Sin derivación de lo anterior.

Todas y cada otro patrón de uso que he encontrado, está hecho para eludir sin entender appenders log4net, incluyendo algunas/todas las respuestas aquí.

+0

Si tengo una única biblioteca (núcleo) de registrador, pero a la que se hace referencia en capas diferentes, esta inicialización estática del registrador siempre mantiene el registrador como biblioteca (principal) pero como biblioteca referenciada. ¿tienes alguna sugerencia para esto? – HydPhani

+0

Parece que no quiere seguir el enfoque que recomiendo aquí, sino que desea ajustar log4net. No lo recomiendo, pero si está desesperado por esto de todos modos, consulte las respuestas aquí: http://stackoverflow.com/questions/166438/what-would-a-log4net-wrapper-class-look-like –

Cuestiones relacionadas