2009-02-17 17 views
25

Mam trudności ze śledzeniem problemu z blokadą, więc chciałbym rejestrować każde wejście i wyjście wywołania metody. Zrobiłem to wcześniej w C++ bez konieczności dodawania kodu do każdej metody. Czy to możliwe z C#?Jak dodać Trace() do każdego wywołania metody w C#?

+0

Zważywszy, że wiesz czego blokowania i grubsza, gdzie to jest, jak o opublikowania kodu ... –

+1

Zmiana środowiska kod jest zepsuty przez automatyczne dodawanie w dodatkową funkcję połączenia mogą modyfikować stan do punktu, w którym martwa blokada już nie występuje. Kod pocztowy może najlepiej rozwiązać problem. –

+0

Po prostu dla zapisu, nie skończyłem w ten sposób. Skończyło się na rozwiązaniu problemu przy użyciu WinDbg i dziesiątek zrzutów stacktrace. –

Odpowiedz

19

Prawdopodobnie najlepszym rozwiązaniem byłoby użycie architektury AOP (ang. Aspect oriented programming) do automatycznego wywoływania kodu śledzenia przed i po wykonaniu metody. Popularnym wyborem AOP i .NET jest PostSharp.

+0

Dzięki - PostSharp nawet pochodzi z przykładowego projektu, który robi coś podobnego. :) –

+1

Niedawno wprowadzono zestaw narzędzi do diagnostyki postsharp http://www.sharpcrafters.com/blog/post/Configuring-PostSharp-Diagnostics-Toolkits.aspx –

2

Użyj ANTS Profiler z Red Gate jako najlepszy zakład. W przeciwnym razie spójrz na interceptors w Castle Windsor. Zakłada to, że ładujesz swoje typy za pomocą IoC.

Odbicie to inny sposób, można użyć metod System.Reflection.Emit do "zapisu" kodu do pamięci. Ten kod może zastąpić kod twojej metody i wykonać ją, ale z odpowiednim logowaniem. Powodzenia na tym, ale ... Łatwiej byłoby użyć ram programowania zorientowanych na aspekt, takich jak Aspect#.

+0

ANTS jest świetny (podobnie jak VS zbudowany w profiler), ale wadą jest to, że możesz zmienić "ślad" pamięci/czasu w aplikacji. i być może nie doświadczysz blokady ... –

+0

Śledzenie również zmieniłoby czas. –

+1

Tak, to zasada nieoznaczoności Heisenberga. Obserwując eksperyment, możesz dobrze zmienić wyniki eksperymentu. To debugowanie synchronizacji wątków dla ciebie ... –

0

Skąd wiadomo, że to się dzieje? Jeśli jest to aplikacja wielowątkowa, poleciłbym testowanie warunku i wywoływanie System.Diagnostics.Debugger.Break() w czasie wykonywania, gdy zostanie wykryty. Następnie wystarczy otworzyć okno wątków i przejść przez stosy wywołań w każdym odpowiednim wątku.

3

Profiler świetnie nadaje się do przeglądania uruchomionego kodu podczas projektowania, ale jeśli szukasz możliwości tworzenia niestandardowych śladów w produkcji, to, jak wspomniał Denis G., PostSharp jest idealnym narzędziem: nie musisz musisz zmienić cały kod i możesz go łatwo włączyć/wyłączyć.

Jest również łatwy do skonfigurowania w kilka minut, a Gaël Fraiteur, twórca PostSharp, ma nawet wideo, które pokazuje, jak łatwo można dodać śledzenie do istniejącej aplikacji.
Znajdziesz przykłady i samouczki w documentation section.

1

Może to oznaczać, że problem blokady został wstrzymany, wykonanie zrzutu pamięci i przeanalizowanie stosu wywołań na różnych wątkach. Możesz użyć DebugDiag lub skryptu adplus (w tym przypadku tryb zawieszenia), który jest dostarczany z Debugging Tools for Windows.

Tess Ferrandez ma również excellent lab series na temat nauki debugowania różnych problemów przy użyciu zrzutów pamięci .NET. Gorąco polecam.

3

Jeśli głównym celem jest, aby zalogować wpis funkcja/punkty wyjścia i okazjonalnych informacji pomiędzy nimi, miałem dobre wyniki z Jednorazowe rejestrowania obiektu, gdzie Konstruktor śledzi funkcję wejścia, i Dispose() śledzi wyjście. Pozwala to na wywoływanie kodu w prosty sposób zawijając kod każdej metody wewnątrz pojedynczej instrukcji przy użyciu instrukcji. Dostarczono również metody dla dowolnych logów pomiędzy.Powyżej znajduje się pełna C# ETW śledzenie zdarzeń klasa wraz z obwolutą wejście funkcji/wyjścia:

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

kod, który wykorzystuje to będzie wyglądać następująco:

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

Spróbuj JetBrains dotTrace jest .NET Performance Profiler. nie musisz modyfikować swojego kodu. i daje ci 10 dni na proces.

Oto poradnik dla dottrace