2009-02-17 13 views
25

Tengo dificultades para localizar un problema de bloqueo, por lo que me gustaría registrar la entrada y salida de cada método. He hecho esto antes con C++ sin tener que agregar código a cada método. ¿Es esto posible con C#?¿Cómo puedo agregar un Trace() a cada llamada de método en C#?

+0

Dado que usted sabe lo que está de bloqueo y más o menos donde está, ¿qué hay de publicar algo de código ... –

+1

Cambiar el entorno de su código está fallando en forma automática mediante la adición de función adicional las llamadas pueden modificar el estado al punto donde el bloqueo muerto ya no se produce. El código de publicación podría ser el mejor para tratar de resolver el problema. –

+0

Solo para el registro, no terminé yendo de esta manera. Terminé resolviendo el problema usando WinDbg y docenas de volcados stacktrace. –

Respuesta

19

Probablemente su mejor opción sea utilizar un marco de AOP (programación orientada a aspectos) para llamar automáticamente al código de rastreo antes y después de la ejecución de un método. Una opción popular para AOP y .NET es PostSharp.

+0

Gracias - PostSharp incluso viene con un proyecto de ejemplo que hace algo similar. :) –

+1

Recientemente se introdujo el kit de herramientas de diagnóstico de postsharp http://www.sharpcrafters.com/blog/post/Configuring-PostSharp-Diagnostics-Toolkits.aspx –

2

Usar ANTS Profiler de Red Gate sería su mejor opción. En su defecto, mira en interceptors en Castle Windsor. Sin embargo, eso supone que estás cargando tus tipos a través de IoC.

Reflexión es otra manera, puede utilizar los métodos System.Reflection.Emit para "escribir" el código en la memoria. Ese código podría reemplazar el código de su método y ejecutarlo pero con el registro apropiado. Buena suerte en eso, sin embargo ... Sería más fácil usar un marco de Programación Orientada a Aspectos como Aspect#.

+0

ANTS es genial (como lo es el generador de perfiles integrado VS), pero el inconveniente es que puede cambiar la memoria/tiempo 'huella' de la aplicación. y posiblemente no experimente el bloqueo ... –

+0

El rastreo también cambiaría el tiempo. –

+1

Sí, es el Principio de Incertidumbre de Heisenberg. Al observar el experimento, puede cambiar los resultados del experimento. Esa es la depuración de sincronización de subprocesos para usted ... –

0

¿Cómo sabes que está sucediendo? Si se trata de una aplicación multiproceso, recomendaría probar la condición y llamar a System.Diagnostics.Debugger.Break() en tiempo de ejecución cuando se detecte. Luego, simplemente abra la ventana de Subprocesos y recorra las pilas de llamadas en cada tema relevante.

3

Un generador de perfiles es ideal para buscar su código de ejecución durante el desarrollo, pero si está buscando la posibilidad de hacer trazas personalizadas en producción, entonces, como mencionó Denis G., PostSharp es la herramienta perfecta: usted no tiene que cambiar todo su código y puede encenderlo/apagarlo fácilmente.

También es fácil de configurar en unos minutos y Gaël Fraiteur, el creador de PostSharp incluso tiene videos que muestran lo fácil que es agregar el rastreo a una aplicación existente.
Encontrará ejemplos y tutoriales en el documentation section.

1

Podría estar esperando a que se produzca el problema de bloqueo, realizando un volcado de memoria y analizando la pila de llamadas en varios subprocesos. Puede usar DebugDiag o el script adplus (modo colgar, en este caso) que viene con Debugging Tools for Windows.

Tess Ferrandez también tiene un excellent lab series para aprender a depurar varios problemas utilizando los volcados de memoria .NET. Lo recomiendo altamente.

3

Si su principal objetivo es registrar la entrada/salida función de los puntos de información y de vez en cuando en el medio, he tenido buenos resultados con un objeto desechable tala donde el constructor traza la entrada de la función, y Dispose() traza la salida. Esto permite que el código de llamada simplemente ajuste el código de cada método dentro de un solo usando la instrucción. También se proporcionan métodos para registros arbitrarios en el medio.Aquí es un evento ETW clase completo en C# trazando junto con un envoltorio de entrada de la función/salida:

using System; 
using System.Diagnostics; 
using System.Diagnostics.Tracing; 
using System.Reflection; 
using System.Runtime.CompilerServices; 

namespace MyExample 
{ 
    // This class traces function entry/exit 
    // Constructor is used to automatically log function entry. 
    // Dispose is used to automatically log function exit. 
    // use "using(FnTraceWrap x = new FnTraceWrap()){ function code }" pattern for function entry/exit tracing 
    public class FnTraceWrap : IDisposable 
    { 
     string methodName; 
     string className; 

     private bool _disposed = false; 

     public FnTraceWrap() 
     { 
      StackFrame frame; 
      MethodBase method; 

      frame = new StackFrame(1); 
      method = frame.GetMethod(); 
      this.methodName = method.Name; 
      this.className = method.DeclaringType.Name; 

      MyEventSourceClass.Log.TraceEnter(this.className, this.methodName); 
     } 

     public void TraceMessage(string format, params object[] args) 
     { 
      string message = String.Format(format, args); 
      MyEventSourceClass.Log.TraceMessage(message); 
     } 

     public void Dispose() 
     { 
      if (!this._disposed) 
      { 
       this._disposed = true; 
       MyEventSourceClass.Log.TraceExit(this.className, this.methodName); 
      } 
     } 
    } 

    [EventSource(Name = "MyEventSource")] 
    sealed class MyEventSourceClass : EventSource 
    { 
     // Global singleton instance 
     public static MyEventSourceClass Log = new MyEventSourceClass(); 

     private MyEventSourceClass() 
     { 
     } 

     [Event(1, Opcode = EventOpcode.Info, Level = EventLevel.Informational)] 
     public void TraceMessage(string message) 
     { 
      WriteEvent(1, message); 
     } 

     [Event(2, Message = "{0}({1}) - {2}: {3}", Opcode = EventOpcode.Info, Level = EventLevel.Informational)] 
     public void TraceCodeLine([CallerFilePath] string filePath = "", 
            [CallerLineNumber] int line = 0, 
            [CallerMemberName] string memberName = "", string message = "") 
     { 
      WriteEvent(2, filePath, line, memberName, message); 
     } 

     // Function-level entry and exit tracing 
     [Event(3, Message = "Entering {0}.{1}", Opcode = EventOpcode.Start, Level = EventLevel.Informational)] 
     public void TraceEnter(string className, string methodName) 
     { 
      WriteEvent(3, className, methodName); 
     } 

     [Event(4, Message = "Exiting {0}.{1}", Opcode = EventOpcode.Stop, Level = EventLevel.Informational)] 
     public void TraceExit(string className, string methodName) 
     { 
      WriteEvent(4, className, methodName); 
     } 
    } 
} 

código que utiliza que se verá algo como esto:

public void DoWork(string foo) 
{ 
    using (FnTraceWrap fnTrace = new FnTraceWrap()) 
    { 
     fnTrace.TraceMessage("Doing work on {0}.", foo); 
     /* 
     code ... 
     */ 
    } 
} 
-1

Trate JetBrains dotTrace es un .NET Perfilador de rendimiento. no tienes que modificar tu código. y le da 10 días para la prueba.

Aquí es un tutorial para dottrace

Cuestiones relacionadas