c# - ejemplo - ¿Cómo configura y habilita log4net para un conjunto de biblioteca de clases independiente?
log4net levels (5)
Solución 1
Una solución para el primer conjunto de restricciones es básicamente ajustar el log4net.LogManager en su propia clase de LogManager como lo han sugerido Jacob , Jeroen y McWafflestix (vea el código a continuación).
Desafortunadamente, la clase Jacob es estática y C # no admite la herencia estática, por lo que no podría simplemente heredarla y anular el método GetLogger. Sin embargo, no hay demasiados métodos en la clase Jacob , por lo que esta es ciertamente una posibilidad.
El otro inconveniente de esta solución es que si tiene una base de código existente (lo que hago en mi caso) tendría que reemplazar todas las llamadas existentes a log4net.LogManager con su clase envoltura. Sin embargo, no es un gran problema con las herramientas de refactorización de hoy.
Para mi proyecto, estos inconvenientes superaban los beneficios de usar una configuración de registro provista por la aplicación de llamada, así que opté por la Solución 2.
Código
Primero, necesitas una clase de contenedor LogManager:
using System;
using System.IO;
using log4net;
using log4net.Config;
namespace MyApplication.Logging
{
//// TODO: Implement the additional GetLogger method signatures and log4net.LogManager methods that are not seen below.
public static class LogManagerWrapper
{
private static readonly string LOG_CONFIG_FILE= @"path/to/log4net.config";
public static ILog GetLogger(Type type)
{
// If no loggers have been created, load our own.
if(LogManager.GetCurrentLoggers().Length == 0)
{
LoadConfig();
}
return LogManager.GetLogger(type);
}
private void LoadConfig()
{
//// TODO: Do exception handling for File access issues and supply sane defaults if it''s unavailable.
XmlConfigurator.ConfigureAndWatch(new FileInfo(LOG_CONFIG_FILE));
}
}
Luego en tus clases, en lugar de:
private static readonly ILog log = LogManager.GetLogger(typeof(MyApp));
Utilizar:
private static readonly ILog log = LogManagerWrapper.GetLogger(typeof(MyApp));
Solución 2
Para mis propósitos, he decidido establecer una solución que cumpla con el segundo conjunto de restricciones. Vea el código de abajo para mi solución.
Desde el documento Apache log4net :
"Un ensamblaje puede optar por utilizar un repositorio de registro nombrado en lugar del repositorio predeterminado. Esto separa por completo el registro del ensamblaje del resto de la aplicación. Esto puede ser muy útil para los desarrolladores de componentes que desean usar log4net para sus componentes pero lo hacen No quiero exigir que todas las aplicaciones que usan su componente tengan conocimiento de log4net. También significa que su configuración de depuración está separada de la configuración de las aplicaciones. El ensamblado debe especificar RepositoryAttribute para establecer su repositorio de registro. "
Código
Coloqué las siguientes líneas en el archivo AssemblyInfo.cs de mi biblioteca de clase:
// Log4Net configuration file location [assembly: log4net.Config.Repository("CompanyName.IntegrationLibName")] [assembly: log4net.Config.XmlConfigurator(ConfigFile = "CompanyName.IntegrationLibName.config", Watch = true)]
Referencias
Fondo
Estoy escribiendo un conjunto de biblioteca de clases en C # .NET 3.5 que se utiliza para la integración con otras aplicaciones, incluidas las herramientas de terceros Commercial-Off-The-Shelf (COTS). Por lo tanto, a veces esta biblioteca de clases será llamada por aplicaciones (EXE) que controlo, mientras que otras veces será llamada por otras DLL o aplicaciones que no controlo.
Suposiciones
- Estoy usando C # 3.0, .NET 3.5 SP1 y Visual Studio 2008 SP1
- Estoy usando log4net 1.2.10.0 o mayor
Restricciones
Cualquier solución debe:
- Permita que la biblioteca de clases habilite y configure el registro a través de su propio archivo de configuración, si la aplicación que realiza la llamada no configura log4net.
- Permita que la biblioteca de clases habilite y configure el registro a través de la configuración de las aplicaciones de llamada, si especifica la información de log4net.
O
- Permita que la biblioteca de clases habilite y configure el registro utilizando su propio archivo de configuración en todo momento.
Problema
Cuando mi biblioteca de clases independiente es llamada por una DLL o una aplicación que no controlo (como una herramienta COTS de terceros) y que no especifica la información de configuración de log4net, mi biblioteca de clases no puede hacer nada de su registro .
Pregunta
¿Cómo se configura y habilita log4net para un conjunto de biblioteca de clases autónomo para que se registre independientemente de si la aplicación de llamada proporciona la configuración de log4net?
En su biblioteca de clases independiente, tenga un singleton que cargue el archivo de configuración log4net
usando el log4net.Config.XmlConfigurator
.
Específicamente, puede definir todo su código para usar su propia clase de registro personalizado; esta clase puede ser simplemente una envoltura simple de las llamadas de registro de log4net, con una adición; crear un miembro estático que contenga la información de registro que desea iniciar sesión; Inicialice eso con una llamada al XmlConfigurator en el constructor estático para esa clase. Eso es todo lo que tienes que hacer.
En su código puede comprobar si hay registradores a través de
log4net.LogManager.GetCurrentLoggers().Count()
Por ejemplo, podría usar un XmlConfigurator para cargar una configuración predeterminada desde un archivo:
log4net.Config.XmlConfigurator.Configure(configFile)
Podrías hacer la inicialización en un constructor estático o regular.
class Sample
{
private static readonly log4net.ILog LOG;
static Sample()
{
if (log4net.LogManager.GetCurrentLoggers().Count() == 0)
{
loadConfig();
}
LOG = log4net.LogManager.GetLogger(typeof(Sample));
}
private static void loadConfig()
{
/* Load your config file here */
}
public void YourMethod()
{
LOG.Info("Your messages");
}
}
Probablemente puedas codificar algo alrededor de la clase XmlConfigurator :
public static class MyLogManager
{
// for illustration, you should configure this somewhere else...
private static string configFile = @"path/to/log4net.config";
public static ILog GetLogger(Type type)
{
if(log4net.LogManager.GetCurrentLoggers().Length == 0)
{
// load logger config with XmlConfigurator
log4net.Config.XmlConfigurator.Configure(configFile);
}
return LogManager.GetLogger(type);
}
}
Luego en tus clases, en lugar de:
private static readonly ILog log = LogManager.GetLogger(typeof(MyApp));
Utilizar:
private static readonly ILog log = MyLogManager.GetLogger(typeof(MyApp));
Por supuesto, sería preferible hacer de esta clase un servicio y configurarlo dinámicamente con el contenedor IoC de su elección, ¿pero entiende la idea?
EDITAR: Se corrigió el problema Count () señalado en los comentarios.
Puede encontrar una buena descripción aquí: log4net: una guía de inicio rápido
Como se describe en el artículo, para configurarlo para cada ensamblaje por separado, cree un archivo XML para su ensamblaje llamado AssemblyName.dll.log4net
y coloque el siguiente código XML en él:
<?xml version="1.0" encoding="utf-8"?>
<log4net debug="false">
<appender name="XmlSchemaFileAppender" type="log4net.Appender.FileAppender">
<file value="AppLog.xml" />
<appendToFile value="true" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<layout type="log4net.Layout.XmlLayout" />
</appender>
<root>
<level value="WARN" />
<appender-ref ref="XmlSchemaFileAppender" />
</root>
</log4net>
Además describe, para crear una instancia de un nuevo registrador, simplemente declararlo como una variable para toda la clase de la siguiente manera:
public class LogSample
{
private static readonly log4net.ILog Log
= log4net.LogManager.GetLogger(typeof(LogSample));
// Class Methods Go Here...
}
Luego puede usar la variable privada Log
dentro de su clase como:
Log.Info("Sample message");
Del mismo modo, puede usar Log.Error("Error occurred while running myMethod", ex)
Para registrar errores junto con los detalles de la excepción.
Lo que encontré es lo siguiente:
No olvide llamar a
log4net.Config.XmlConfigurator.Configure();
para activar tu configuracionSi necesita conocer la ruta de los archivos escritos, here algunos códigos sobre cómo obtenerlos de Log4Net
Espero que esto ayude.