¿Cómo puedo agregar un Trace () a cada llamada de método en C #?

Me está costando localizar un problema de locking, 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 #?

Probablemente su mejor opción sea utilizar un marco AOP (progtwigció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 .

Un generador de perfiles es ideal para ver su código de ejecución durante el desarrollo, pero si está buscando la posibilidad de realizar trazados personalizados en producción, entonces, como mencionó Denis G., PostSharp es la herramienta perfecta: no tiene que cambiar todo su código y puede activarlo / desactivarlo fácilmente.

También es fácil de configurar en pocos 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 la sección de documentación .

Si su objective principal es registrar puntos de entrada / salida de funciones e información ocasional entre ellos, he tenido buenos resultados con un objeto de registro desechable donde el constructor rastrea la entrada de la función y Dispose () rastrea la salida . Esto permite que el código de llamada simplemente ajuste el código de cada método dentro de una única statement de uso . También se proporcionan métodos para registros arbitrarios en el medio. Aquí hay una clase de seguimiento de eventos C # ETW completa junto con un contenedor de entrada / salida de funciones:

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); } } } 

El código que lo usa se verá algo como esto:

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

Usar ANTS Profiler de Red Gate sería tu mejor opción. Si eso falla, mira los interceptores en Castle Windsor . Sin embargo, eso supone que estás cargando tus tipos a través de IoC.

Reflexión es otra manera, puede usar los métodos System.Reflection.Emit para “escribir” 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 … Más fácil sería usar un marco de Progtwigción Orientada a Aspectos como Aspecto # .

Podría estar esperando que el problema de locking se arraigue, haciendo un volcado de memoria y analizando la stack de llamadas en varios subprocesos. Puede usar DebugDiag o el script adplus (modo colgar, en este caso) que viene con las herramientas de depuración para Windows .

Tess Ferrandez también tiene una excelente serie de laboratorio sobre cómo aprender a depurar varios problemas usando volcados de memoria .NET. Lo recomiendo altamente.

¿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 stacks de llamadas en cada tema relevante.

si tiene un problema de interlocking, consulte http://www.codeproject.com/KB/dotnet/Deadlock_Detection.aspx

Prueba jetbrains dottrace, es un .NET Performance Profiler. no tienes que modificar tu código. y le da 10 días para la prueba.

Aquí hay un tutorial para dottrace