2009-03-26 21 views
8

Con frecuencia me siento frustrado por la cantidad de registros que tengo que incluir en mi código y me lleva a preguntarme si existe una forma mejor de hacer las cosas.¿Es posible el registro pasivo en .NET?

No sé si esto se ha hecho o si alguien ha tenido una mejor idea, pero me preguntaba si hay alguna forma de que alguien sepa de "inyectar" un registrador en una aplicación para que monitoree pasivamente el enhebrar y registra en silencio los procesos que se producen sin tener que hacer cosas como:

public void MyProcess(int a, string b, object c) 
{ 
    log(
    String.Format(
     "Entering process MyProcess with arguments: [a] = [{0}]; [b] = [{1}]; [c] = [{2}]", 
     a.ToString(), 
     b, 
     c.ToString() 
); 

    try 
    { 
    int d = DoStuff(a) 
    log(
     String.Format(
     "DoStuff({0}) returned value {1}", 
     a.ToString(), 
     d.ToString() 
    ) 
    ); 
    } 
    catch (Exception ex) 
    { 
    log(
     String.Format("An exception occurred during process DoStuff({0})\nException:\n{1}", 
     a.ToString(), 
     ex.ToString()) 
    ) 
    } 
} 

¿Cuál sería grande es si podría decirle a mi registrador:

Monitor(MyClass.MyMethod) 

sería entonces monitorear todo lo que pasa dentro de ese método, incluidos argumentos pasados ​​a lo largo de wi las llamadas al método y los valores pasados ​​a esos métodos, excepciones que ocurren, etc.

¿Alguien ha implementado algo como esto en el pasado? ¿Podría incluso ser implementado? ¿Iniciar sesión de esta manera es solo un sueño?

Me encantaría diseñar algo que hiciera esto, pero simplemente no sé dónde comenzaría. Por supuesto, tampoco quiero reinventar la rueda, si ya está hecho, sería genial si alguien pudiera señalarme en la dirección correcta.

Cualquier sugerencia sería bien recibidas ...

Editar: pensé que comentar sobre una respuesta que preguntó en cuanto al nivel de detalle requerido en el registro. A menudo se requiere que se proporcionen niveles de registro configurables, de modo que si la configuración especifica un registro detallado, todo se registra, mientras que si se configura el registro crítico, solo se registra cierta información junto con las excepciones. Si se configura el registro fatal, entonces solo se registrará la información que causa la muerte de la aplicación. ¿Sería algo así configurable o el AOP requeriría 3 o 4 compilaciones diferentes según el número de niveles de registro?

frecuencia utilizo 4 niveles: Fatal, crítico, información, detalladas

+0

Esto podría ser configurable en tiempo de ejecución pero luego el registrador que se ejecuta durante el tiempo de ejecución aún recibiría toda la información y luego tendría que decidir qué registrar. Si no quiere que la sobrecarga de toda la información pase al registrador, entonces la única forma sería tener diferentes compilaciones. –

Respuesta

9

Puede utilizar PostSharp para registrar el método de "alrededor". Este es exactamente el tipo de cosas en las que AOP es bueno. Es posible que desee comenzar con Log4PostSharp, un complemento específico para el registro.

+0

Tuve problemas con PostSharp en el pasado; no se combinó bien con Team Build. Realmente edita el IL generado por los compiladores, y se confundió acerca de dónde escribir los binarios editados. Tal vez ya esté arreglado. Me puso nervioso tener mi IL reescrito en cualquier caso. –

+0

¿Siente usted la misma reserva sobre los Contratos de Código, por interés? –

+0

No lo sé; ¿Reescribe IL? ¿Utiliza escenarios probados por Microsoft? Me preocupaba que PostSharp fuera el único o uno de los pocos códigos que reescribía IL, y que Team Build etc. podría no tener eso en cuenta. URL para "Contratos de código", por favor? –

4

Este es el ejemplo clásico de la Programación Orientada a Aspectos. Ver PostSharp para una muy buena biblioteca basada en CLR.

4

Este es uno de los libros de texto (no estoy seguro de qué libro de texto tiene AoP pero le da la idea) ejemplos de AoP - logging: donde quiere pegar algo antes y después de un método.

Es posible que desee explorar la ruta de AoP, PostSharp es uno de los populares, junto con Microsoft Unity (IoC también), Castle.

Un ejemplo simplista de AoP es que agrega su código antes y después de los métodos, en lugar de agregar las llamadas al método dentro de los métodos reales. Al etiquetar la pregunta con C#, es posible que desee buscar un método de extensión para iniciar sesión, que ya está en this question.

Me gustaría tener un enfoque práctico: ¿cuánta tala real estás haciendo?¿Puedes salirte con un solo método de extensión en lugar de deslumbrar a la persona que lee tu código? El registro built into the .NET framework ya es decente.

+0

Bueno, pensé en seguir con los métodos de extensión, pero el cliente quiere un registro de nivel variable definido por el archivo de configuración, por lo que dependiendo del nivel de registro especificado en el archivo de configuración, depende de qué tan detallado sea el registro. ¿Qué tipo de esto impide? – BobTheBuilder

+0

Todo esto se puede definir en un archivo de configuración, información/advertencia/error y una categoría –

+0

. Ya sea PostSharp o lo que sea, debe buscar en Enterprise Library para su API de registro. Puede configurar lo que se registra, dónde y en qué formato. –

1

Además de los métodos de registro mencionados por Jon, probablemente también valga la pena notar otra característica útil en VS para rastrear el flujo del programa, y ​​es la capacidad de tener puntos de corte sin interrupción que simplemente generarán un mensaje o ejecutarán una macro cuando se golpea (tenga en cuenta que también puede imprimir valores variables)

Haga clic con el botón derecho en su punto de interrupción y elija la opción de menú contextual When Hit ....

Y, por supuesto, otra característica muy útil es el objeto Trace y los Listadores de seguimiento en System.Diagnostics.

+0

Utilizo esta característica y es excelente durante la fase de desarrollo, pero no ayuda a los clientes a depurar aplicaciones en su entorno de producción de forma independiente, que generalmente es lo que se necesita en este escenario. – BobTheBuilder

0

He escrito recientemente una biblioteca de registro que usa la interfaz IDisposable para envolver regiones con contexto de registro. Básicamente, hay un objeto desechable LogSite que utilice la siguiente manera:

using(var logger = new LogSite("methodName", new object[] { p1, p2, p3 }) 
{ 
    // code that does stuff goes here 
} 

El objeto LogSite tiene un montón de sobrecargas convenientes para el constructor como MethodBase lo que sólo puede utilizar MethodBase.GetCurrentMethod() y utilizar la reflexión para obtener el nombre real del método y los parámetros (en lugar de una cadena codificada).

La forma en que funciona es esta: en el constructor, escribe en el registro con toda la información de seguimiento para indicar que ingresó al bloque. En el método Dispose, escribe una entrada de salida.

Al desechar, también comprueba Marshal.GetExceptionCode() para un valor distinto de cero para ver si el código dentro del uso arrojó una excepción o salió normalmente. No le da la excepción, por lo que tendrá que registrarse explícitamente en el controlador catch, pero indica "pasa/falla" para esa región. Esto permite que su ámbito de registro sea más específico que solo el método, ya que podría tener muchos de estos bloques en un solo método, y saber cuál arrojó la excepción exactamente.

Además, dado que hay un objeto "registrador" ya está disponible, el controlador de captura sólo se parece a:

try { ... } 
catch (Exception ex) 
{ 
    logger.LogException(ex); 
} 

El registrador ya se conoce el nombre del método, los parámetros, y todo eso, y tiene métodos internos para formatear la información de la excepción.

Entrando en la arquitectura debajo de este objeto de alto nivel, hay un concepto de "LogDisposition" que maneja el "aprobado/no" que determinamos anteriormente, y hay un concepto de "LogEntryType" que es un filtro (implementado con Flags enum) que indica qué tipo de entrada de registro se está pasando (Error, Trace, etc.).

Lo que realmente hace el registro es solo un patrón editor/oyente. El editor toma la entrada de registro pasado, y al igual que un delegado de múltiples lanzamientos, mantiene un registro de instancias de LogListener (debe configurarse al inicio del programa o agregarse dinámicamente según sea necesario) y pasa la entrada de registro a esas instancias .

Los LogListeners, a su vez, filtran el tipo de entradas de registro que les interesan ... Por lo tanto, si no desea los puntos de entrada y salida del método para las condiciones sin errores, no tienen que aparecer en el Iniciar sesión. Esto se puede controlar en tiempo de ejecución para permitir al usuario hacer cosas como activar y desactivar el registro detallado a voluntad. Como el editor puede escribir en una variedad de loglisteners, puede conectar algo que se escribe en un archivo, o escribe en la base de datos, o muestra notificaciones de error en la GUI ... etc.

Es un sistema bastante bueno, y requiere una cantidad relativamente pequeña de codificación para obtener un registro relativamente rico.

Podría darle una muestra del código si quisiera ... Puede contactarme a través de mi blog (casi completamente inactivo) (vea el perfil de mi cuenta).

Espero que ayude.

0

Utilizo el código abierto Apache log4net en todos mis proyectos. Es una aplicación muy simple con todo tipo de extensiones que le permiten conectarse a bases de datos, archivos zip, archivos de registro de rodadura, feeds RRS, los clientes Telnet, etc. La explotación forestal es básicamente tan simple como:

'Will print stack trace after message' 
log.err(ex.message,ex) 

log.warn("warn") 
log.info("info") 
log.debug("debug") 

parámetros de registro tales ya que el formato de salida y el nivel de registro a la salida se leen en tiempo real mientras su aplicación está en tiempo de ejecución.

Cuestiones relacionadas