2010-11-29 17 views
11

Tengo pocos servicios web diferentes expuestos por mi sitio web. Aquí hay unos objetivos que quiero alcanzar:log4net: cómo personalizar los datos que se almacenarán

  1. Almacenar todos los datos en DB en una tabla;
  2. Cada registro debe tener un campo de texto con el nombre 'servicio/componente';
  3. Es necesario almacenar todos los parámetros de ingresos cuando se llama a cualquier método;
  4. Es necesario almacenar todos los parámetros de resultados Y mensajes de error si se produce alguna excepción.

Mi intención original era usar log4net. Pero de estas visitas (http://sadi02.wordpress.com/2008/09/15/how-to-store-log-in-database-using-log4net/, http://logging.apache.org/log4net/release/config-examples.html) no veo una manera fácil para agregar datos personalizados en la tabla de registro.

¿Es factible usar log4net para tales fines? ¿Cómo puedo cambiar el esquema de la tabla de registro para almacenar datos personalizados? ¿Debo modificar el código fuente de la biblioteca log4net? ¿Probablemente sería mejor escribir una funcionalidad personalizada para almacenar ese tipo de datos?

Gracias.

Respuesta

2

Ninguna de las respuestas sugeridas funciona para mí. El problema es que necesito tener varios campos personalizados. Para mí, parece demasiado complicado crear diferentes instancias de registrador o configurar valores de columna cada vez a través de las 'propiedades'.

Voy a ir (en realidad, ya implementado) registrador personalizado que pone datos en DB.

1

Al mirar la documentación de log4net, ¿puede averiguar cómo obtener sus datos personalizados registrados en un archivo? Si es así, también debería poder obtener esos mismos datos registrados en la base de datos. Solo agregue más columnas en su tabla, más columnas en el nodo <command text> de AdoNetAppender, y más nodos <parameter>.

Creo que tendrá algo de trabajo para hacer que sus parámetros entrantes y salientes sean registrados. ¿Los necesita registrados en columnas separadas (probablemente no sean fáciles de limpiar)? ¿Está bien si se registran junto con el mensaje?

Por ejemplo, si usted tiene el siguiente método que desea poner ingresando a:

public void DoSomething(int x, int y) 
{ 
    log.Info("Inside DoSomething"); 
} 

¿Qué desea obtener la salida para parecerse? ¿Desea que la información log4net "estándar" aparezca en columnas separadas (marca de tiempo, nombre del registrador, nivel, mensaje)? ¿Y los parámetros? En caso de que x e y aparecer en columnas separadas (probablemente no es muy fácil de hacer a menos que cada método tiene el mismo número de parámetros) o sería ok si los parámetros se registran como esto:

public void DoSomething(int x, int y) 
{ 
    ILog log = LogManager.GetLogger("abc"); 
    log.InfoFormat("Parameters: x = {0}, y = {1}", x, y); 
    log.Info("Inside DoSomething"); 
} 

Las declaraciones de registro generará mensajes se verá algo como esto:

11/29/2010 16:36:00 | abc | INFO | Parameters: x = 10, y = 20 
11/29/2010 16:36:00 | abc | INFO | Inside DoSomething 

He utilizado | carácter para mostrar lo que serían los campos con un diseño de patrón que muestra la marca de tiempo, el nombre del registrador, el nivel de registro y el mensaje.

Ver una solución de AOP como PostSharp podría ayudarlo porque podría agregar de manera relativamente fácil el registro de entrada/salida sin "contaminar" el código fuente de su aplicación con las declaraciones de registro. Dentro del "aspecto" de registro, usted tendría acceso a los parámetros del método.

Me podría estar faltando algo, pero sospecho que si desea mantener sus parámetros de método como columnas individuales en la base de datos, entonces le resultará difícil hacerlo. Si está satisfecho con la combinación de todos los parámetros (manualmente) para cada método como una sola columna (esencialmente una cadena formateada), entonces será más fácil.Un precio que tendrá que pagar es que tendrá que registrar explícitamente todos los parámetros (a menos que vaya por la ruta AOP).

Si está considerando usar log4net, también debería considerar usar NLog. No necesariamente lo ayudará con los problemas que describí anteriormente, pero creo que es un competidor digno de log4net.

[EDIT]

Para obtener el "nombre del componente" registrado por log4net, debe asignar nombres a los registradores para sus componentes. Cuando llama a LogManager.GetLogger (nombre), puede pasar cualquier nombre (o tipo). Un patrón común es tener un código como éste en cada clase:

public class MyClass 
{ 
    private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 

    public void DoSomething(int x) 
    { 
    logger.InfoFormat("Inside DoSomething. x = {0}", x); 
    } 
} 

Esto hará que un registrador de llamada con el nombre de clase completo (espacio de nombre + nombre de la clase). Si haces esto en todas las clases, entonces puedes controlar el registro (nivel, a qué apéndice va, etc.) por clase. Por lo tanto, podría convertir fácilmente el registro para Class1 en Info y el registro para Class2 Off, etc. Esto le da el potencial para el mayor grado de control de su registro.

Ahora, en su archivo de configuración, no está obligado a enumerar cada registrador (es decir, cada nombre de clase completamente calificado) explícitamente. Podrías simplemente configurar el registrador de raíz y luego esa configuración se aplicaría a cada registrador. Podrías controlar tu registro por espacio de nombres. Por ejemplo, si usted trabaja para CompanyX y tiene reglas de espacio de nombres explícitos, los espacios de nombres podrían ser:

CompanyX 
CompanyX.DataAccess 
CompanyX.DataAccess.Read 
CompanyX.DataAccess.Write 
CompanyX.GUI 
CompanyX.Forms 
CompanyX.Controls 

Dentro de cada espacio de nombres, es posible que tenga varias clases (al igual que varios lectores de datos diferentes, clases de ayuda, escritores de datos, etc.) Con sus clases organizadas de esta manera y con sus clases obteniendo registradores como se indicó anteriormente, podría configurar fácilmente el registro para todas las clases en CompanyX, o todos los registradores en CompanyX.DataAccess, o CompanyX.DataAccess.Read, etc. Incluso podría desactivar todo el inicio de sesión , pero enciéndelo para esa clase problemática que te está dando problemas.

También puede obtener sus registradores por nombres arbitrarios (es decir, no tiene que usar el nombre de clase si no desea). Se podría definir áreas funcionales en su aplicación (s) y obtener madereros sobre la base de que:

ILog logger = LogManager.GetLogger("DataAccess"); 
ILog logger = LogManager.GetLogger("Performance"); 
ILog logger = LogManager.GetLogger("UI"); 

Y así sucesivamente. No veo que esto proporcione muchos beneficios con respecto al uso del nombre de clase completo. Si su (s) espacio (s) de nombre están bien organizados, entonces su capacidad para configurar su registro tendrá la máxima flexibilidad con el mínimo esfuerzo de su parte.

Otra palabra en NLog ... NLog es muy similar a log4net. Se tiene la característica útil de ser capaz de devolver automáticamente un registrador para la clase actual:

Logger logger = NLog.LogManager.GetCurrentClassLogger(); 

Esto ahorra al menos algo de tecleo de su parte. NLog también acaba de lanzar una nueva versión (actualmente en versión beta).

No sé si algo de esto ayudó, ¡pero espero que sí!

¡Buena suerte!

+0

Está bien tener todos los parámetros en 1 campo, pero (como mencioné en el comentario a otra respuesta) me gustaría tener el nombre del componente en una columna separada (sin cambiar el contexto global para cada llamada). También me gustaría tener 3 columnas adicionales: income_data, outcome_data, error_message. Probablemente, podría configurar pocas instancias de registrador diferentes (1 por componente)? ¿Y en este caso no necesitaré cambiar la configuración global cada vez? Lo siento, soy nuevo con log4net. – Budda

+0

Sí, es probable que desee tener al menos un registrador por componente. He agregado algunos ejemplos en mi respuesta. – wageoghe

14

De acuerdo con este discussion, el proceso es bastante sencillo.

El primer paso es actualizar el texto de comando en la declaración appender en el fichero de configuración:

<commandText value="INSERT INTO Log4Net ([Date],[Thread],[Level],[Logger],[Message],[Exception],[MyColumn]) VALUES (@log_date, @thread, @log_level, @logger, @message, @exception,@MyColumn)"/>   

El siguiente paso es y añadir una nueva definición de parámetros para la columna personalizada:

<parameter> 
    <parameterName value="@MyColumn "/> 
    <dbType value="String" /> 
    <size value="255" /> 
    <layout type="log4net.Layout.PatternLayout"> 
     <conversionPattern value="%property{MyColumn}" /> 
    </layout> 
</parameter> 

por último, se puede acceder al valor medio de las propiedades GlobalContext de log4net:

log4net.GlobalContext.Properties["MyColumn"] = "MyValue"; 
log.Debug("My message"); 

Puede hacer esto para tantos campos como necesite.

+0

¿Entiendo correctamente que antes de cada escritura debo configurar el valor correcto de "MyColumn"? Por ejemplo, mi sitio web tiene que admitir 3 "componentes" diferentes. Quiero tener el nombre del componente en una columna separada, en este caso, ¿debo configurar la propiedad "MyComponent" del contexto global antes de cada llamada? No creo que sea lo que necesito (también tendré que manejar la concurrencia) ... – Budda

+0

Probablemente, podría configurar algunas instancias de registrador diferentes (1 por componente)? ¿Estoy en lo cierto con esta suposición? ¿Y en este caso no necesitaré cambiar la configuración global cada vez? Lo siento, soy nuevo con log4net. – Budda

+0

@Budda Sí, necesitaría repetir los valores según sea necesario para cada instancia de "MyColumn" que necesite. En cuanto a los componentes, tendría que configurar uno para cada instancia, pero recuerde que todos los appenders usan los mismos datos de registro, por lo que fácilmente podría tener un proceso de agregación de bases de datos MyColumn1 y el segundo proceso de complementos MyColumn2 si fuera necesario. –

Cuestiones relacionadas