2009-08-28 20 views
9

Básicamente quiero escribir un logger/tracer del cliente que también registra la clase y el nombre del método que llama al logger/tracer. Esto debe ser rápido para que no afecte el rendimiento de la aplicación, fuertemente tipado y limpio. ¿Alguien tiene buenas ideas?¿Cuál es la forma más eficaz de registrar el nombre de clase y método?

Éstos son los pocos que tenía pero me preocupa el rendimiento debido a la reflexión: (¿demasiado trabajo)

  • StackTrace/StackFrame

  • MethodInfo.GetCurrentMethod() (siendo demasiado lento? y no muy limpio) método

  • pase como delegado (C# puede hacerlo de forma implícita y tengo acceso a la MethodInfo, pero no muy limpio)

Agradezco los comentarios de cualquier persona.

ACTUALIZACIÓN:

Me gustó la cleanless de StackFrame por lo que hizo una pregunta más específica here con respecto a la actuación de StackFrame y me dio la muy buena respuesta que incluye pruebas de rendimiento. Resulta que MethodInfo.GetCurrentMethod() es el más rápido (toma aproximadamente 1 microsegundo en mi computadora) y new StackFrame(1) se puede solicitar bajo demanda (toma alrededor de 15-20 microsegundos en mi computadora). Lancé el método como opción de delegado, ya que es demasiado complicado cuando el método tiene varios parámetros.

CONCLUSIÓN:

He mirado todas las opciones y el mejor es escribir un plug-in personalizado para PostSharp que inyecta el nombre del método como cadena en MSIL durante la compilación cuando se aplica un atributo personalizado como [Trace] a él. Es la opción más rápida y más fácil de mantener en mi opinión. Esto incluso permite muchas cosas más, como pasar los nombres y argumentos de los parámetros sin ningún tipo de reflexión y excepciones de captura y registro de forma automática. Esto my related question para más información.

+0

¿Puedo preguntar, por qué no quiere usar log4net? – nWorx

+0

No me gusta depender demasiado de otros componentes. Y también en el caso de log4net, es demasiado complejo. –

+2

Hermann, esto se conoce generalmente en nuestra industria como "síndrome no inventado aquí" y es mejor evitarlo. Aquí hay un enlace de wikipedia con más información sobre esta aflicción: http://en.wikipedia.org/wiki/Not_Invented_Here –

Respuesta

3

En pocas palabras, la manera más rápida de hacerlo es estáticamente en tiempo de compilación:

public void DoSomething() 
{ 
    TraceCall("DoSomething"); 
} 

public void TraceCall(string methodName) 
{ 
    if (!tracingEnabled) { return; } 
    // Log the call 
} 

La pregunta entonces es esencialmente el mismo que su pregunta anterior; ¿Cuál es la mejor manera de hacer esto en un ayuno sostenible y preciso? Las opciones de tiempo de ejecución que discutimos anteriormente tienen un impacto de rendimiento relativamente grave, pero la compensación es que se pueden implementar fácilmente.

Como se mencionó en el hilo anterior, esto está comenzando a inclinarse hacia la Programación Orientada a Aspectos; PostSharp es una de esas bibliotecas que puede ayudar a encontrar el equilibrio del rendimiento compilado estáticamente con un mantenimiento simple.

+0

Tienes razón. Espero que esto no requiera demasiado esfuerzo para implementar esto con PostSharp. Supongo que depende de cada individuo las necesidades, pero no llamaría a 20 microsegundos un golpe de rendimiento severo. –

+0

@Hermann: a menos que esté escribiendo algo que deba manejar el rendimiento de Google, 20ms es totalmente insignificante. Las pruebas que hicimos en la otra pregunta mostraban que si necesita iniciar llamadas de registro para 100.000 métodos, agregaría, como máximo, 1.5 segundos. Independientemente del hecho de que algunos métodos son sustancialmente más rápidos que otros, todos los métodos son marginales al final del día. – STW

2

Cuando ya estás dentro del método (o si estás interceptando el método), no creo que puedas hacer mucho mejor que MethodInfo.GetCurrentMethod, que no es demasiado terriblemente rápido, si quieres quedarte tipo -seguro.

Como desea hacer esto para el registro, ¿ha considerado hacer esto en una operación asincrónica para que no disminuya la velocidad del hilo principal?

Dependiendo de la carga que ya tenga su aplicación, puede o no ayudar.

+0

Sí, estaba pensando en eso también. Pero, ¿qué sucede cuando la aplicación está ocupada? ¿No pospondría eso la tala y no se perdería cuando la aplicación falle? –

+0

Depende de cómo implemente la operación asincrónica. Si solo lo tiras en el ThreadPool, entonces, sí, estás en lo correcto y el pedido no está garantizado. Sin embargo, también puede escribirlo en MSMQ, lo que puede proporcionarle un registro duradero y ordenado. –

+1

La opción asíncrona solo aliviaría la escritura real en el registro (lo que aún podría ser beneficioso). La llamada real "GetCurrentMethod" aún impondría la penalización de rendimiento en el hilo principal. – STW

0

La mejor manera de hacerlo es en tiempo de compilación: C++ utilizó tradicionalmente los símbolos de preprocesador ____FILE____ y ​​____LINE____ en las macros para hacer esto. Desafortunadamente, el compilador de C# no ofrece macros o un equivalente a ____FILE____ y ​​____LINE____ en este momento.

Esto significa que su única opción es registrar esta información en tiempo de ejecución, lo que significa agregar tediosamente el seguimiento manual a cada método que desee registrar o aprovechar el reflejo como se describe.

0

Creo que Log4PostSharp haría el trabajo muy bien.

+0

No quiero usar otro registrador, especialmente no algo basado en log4net, pero realmente me gusta la idea de inyectando código MSIL. Tendré que investigar si puedo usar eso de alguna manera. –

+0

La respuesta de Reading Stu: tardaría aprox. una hora para desarrollar el equivalente de __FILE__ y __LINE__ usando PostSharp (o __TYPE__ y __METHOD__). Bueno, 1 hora para mí. –

+0

Echaré un vistazo a PostSharp. Gracias Gael! –

0

Si le preocupa la velocidad, el mensaje de registro real debe crearse usando Event Tracing for Windows. ETW es una biblioteca de registro de alta velocidad implementada como un controlador al que se puede acceder desde el Modo Kernel y el Modo Usuario. El seguimiento se puede activar y desactivar dinámicamente. El registro agrega muy poca sobrecarga a la aplicación. He usado ETW para implementar el rastreo en aplicaciones de servidor de alto rendimiento. Consulte NTrace.

4

La forma más rápida es hacer eso en tiempo de compilación, es cierto, pero la forma más conveniente de hacerlo en .NET es mediante el uso de las CallerMemberName, CallerFilePath y otros servicios compilador atributos incroduced en .NET 4.5:

public void TraceMethodCall([CallerMemberName]string methodName) 
{ 
} 
Cuestiones relacionadas