2009-06-24 2 views
13

Zuerst das Problem: Ich habe mehrere freie Projekte, und wie jede Software enthalten sie Fehler. Einige Mitbenutzer melden mir einen Bug-Report mit Stack-Traces. Um das Finden der Fehlerstelle zu vereinfachen, möchte ich Zeilennummern in diesem Stapel anzeigen lassen. Wenn die Anwendung ohne .pdb-Dateien ausgeliefert wird, gehen alle Zeileninformationen verloren. Daher werden derzeit alle meine Projekte mit PDB-Dateien bereitgestellt und die so erzeugten Stack-Traces haben diese Nummern. Aber! Aber ich möchte diese Dateien nicht in der Distribution sehen und alle .pdb entfernen wollen. Sie verwechseln Benutzer verbrauchen Raum im Installateur etc.Stack-Trace mit Zeilennummern aus dem Benutzer-Fehlerbericht in .net neu erstellen?

Delphi Lösung: Vor langer Zeit, als ich ein delphi Programmierer war, habe ich die folgende Technik: auf Ausnahme meine Anwendung zu Fuß auf dem Stapel und sammle Adressen. Dann, wenn ich einen Fehlerbericht erhalte, habe ich ein Werkzeug verwendet, das eine gültige Stapelverfolgung mit Funktionsnamen und Zeilennummern basierend auf gesammelten Adressen und entsprechenden Symboldateien auf meinem Rechner rekonstruiert.

Frage: Gibt es Lib, oder Technik oder was auch immer, um das gleiche in .NET zu tun?

Status-Update: Sehr interessant, dass oft eine Frage zu stellen der beste Weg ist, um Ihre eigenen Untersuchungen zu starten. Ich denke zum Beispiel über dieses Problem seit einiger Zeit nach, aber ich suche erst vor ein paar Tagen nach einer Antwort.

Option 1: MiniDumps. Nachdem ich viel gegoogelt habe, habe ich einen Weg gefunden, Mini-Dumps aus Code zu erstellen und Stacks aus verwalteten Mini-Dumps neu zu erstellen.

Diese Lösung jedoch müssen zwei zusätzliche Baugruppen (~ 1 MB groß) verteilen, und Mini-Dumps benötigen etwas Platz, und es ist unangenehm für den Benutzer, sie per E-Mail zu senden. Für meine Zwecke ist es im Moment nicht akzeptabel.

Option 2: Danke an weiqure for clue. Es ist möglich, verwalteten IL-Offset für jeden Stapelrahmen zu extrahieren. Jetzt besteht das Problem darin, Zeilennummern aus .pdb basierend auf diesen Offsets zu erhalten. Und was habe ich gefunden:

Mit diesem lesen Werkzeug, ist es möglich, XML-Dateien für jeden Release-Build zu erstellen und sie in Repositary. Wenn eine Ausnahme auf dem Computer des Benutzers auftritt, ist es möglich, eine formatierte Fehlermeldung mit IL-Offsets zu erstellen. Dann sendet der Benutzer diese Nachricht (sehr klein) per Post. Und schließlich ist es möglich, ein einfaches Werkzeug zu erstellen, das den resultierenden Stapel aus einer formatierten Fehlermeldung neu erstellt.

Ich frage mich nur, warum niemand sonst ein Werkzeug wie dieses implementiert? Ich glaube nicht, dass das nur für mich interessant ist.

+0

FYI: In Delphi ist dies jetzt einfach, weil es madExcept gibt, das einen Stapel-Trace und andere nützliche Informationen in einen Bericht über (nicht behandelte) Ausnahmen legt. – schnaader

+1

Welche Option haben Sie gewählt? Ich suche auch selbst nach einer Lösung. – Giorgi

+1

Ich wählte die zweite Option und schreibe eine Menge von Klassen, um den internen Ausnahme-Dump zu ersetzen. Ich plane auch einen Artikel über meine Lösung mit allen Informationen und Quellen zu schreiben. – arbiter

Antwort

2

Sie können einen Anwendungs-Minidump immer dann erstellen, wenn ein Fehler vorliegt, und ihn für die Offline-Analyse verwenden. Dies erfordert nicht, dass Sie pdbs auf dem Clientcomputer bereitstellen müssen. This Link kann als guter Ausgangspunkt für das Lernen dienen.

+0

Interessanter Artikel, aber es braucht mehr Zeit zum Nachdenken. Und im Allgemeinen ist es hauptsächlich zum Debuggen (nicht Stack-Erholung), und erfordern auch eine Menge von Aktionen des Benutzers. – arbiter

+0

Ich kenne mich nicht mit C# .Net aus, aber in WIN32 C++ - Anwendungen sind Minidumps sehr effektiv, um Probleme mit Kundenwebsites zu analysieren. Ich denke, etwas ähnliches muss auch für C# existieren. – Canopus

+1

Minidumps sind sehr nützlich für Native C++ - Code. Aber ich habe keine Möglichkeit gefunden, eine .NET-Stack-Ablaufverfolgung aus einer Minidump-Datei neu zu erstellen! – mmmmmmmm

5

Sie sollten Environment.FailFast verwenden, FailFast im Application.UnhandledException aufrufen und eine Dump-Datei wird für Sie erstellt.

Aus der MSDN:

Die FailFast Methode einen Protokolleintrag in dem Windows-Ereignisprotokoll Anwendung mit den Nachrichtenparametern, erstellt eine Dump Ihrer Anwendung, und beendet dann den aktuellen Prozess schreibt.

die FailFast Methode Verwenden Sie anstelle der Beenden Methode, um Ihre Anwendung zu beenden, wenn der Zustand Ihrer Anwendung irreparabel beschädigt wird, und Ihre Anwendung Try-finally-Blöcke und Finalizers Ausführung wird korrupte Programmressourcen. Die FailFast-Methode beendet den aktuellen Prozess und führt alle CriticalFinalizerObject-Objekte aus, aber führt keine aktiven Try-finally-Blöcke oder Finalizer aus.

Sie können eine einfache App schreiben, die die Protokolldateien sammelt und Ihnen sendet.

Jetzt ist das Öffnen der Dump-Datei ein wenig schwierig, Visual Studio kann verwaltete Dump-Datei nicht behandeln (behoben in. NET 4.0) Sie können WinDBG verwenden, aber Sie müssen SOS verwenden.

+3

Nicht geeignet für meine Bedürfnisse: 1. Die meisten Ausnahmen sind wiederherstellbar, daher muss die App Informationen anzeigen (optional an die Mail senden) und fortfahren. Mit dieser Methode wird die App bei jeder nicht behandelten Ausnahme vernichtet. 2. Diese Methode erfordert viel Aktion vom Benutzer, um Ausnahmeinformationen an mich zu senden. Fast niemand wird das tun. Sie können von Benutzern erwarten, dass sie Informationen aus dem Fehlerdialog kopieren und anschließend per E-Mail versenden können. – arbiter

12

Sie können den Offset der letzten MSIL Anweisung von der Exception mit System.Diagnostics.StackTrace erhalten:

// Using System.Diagnostics 
static void Main(string[] args) 
{ 
    try { ThrowError(); } 
    catch (Exception e) 
    { 
     StackTrace st = new System.Diagnostics.StackTrace(e); 
     string stackTrace = ""; 
     foreach (StackFrame frame in st.GetFrames()) 
     { 
      stackTrace = "at " + frame.GetMethod().Module.Name + "." + 
       frame.GetMethod().ReflectedType.Name + "." 
       + frame.GetMethod().Name 
       + " (IL offset: 0x" + frame.GetILOffset().ToString("x") + ")\n" + stackTrace; 
     } 
     Console.Write(stackTrace); 
     Console.WriteLine("Message: " + e.Message); 
    } 
    Console.ReadLine(); 
} 

static void ThrowError() 
{ 
    DateTime myDateTime = new DateTime(); 
    myDateTime = new DateTime(2000, 5555555, 1); // won't work 
    Console.WriteLine(myDateTime.ToString()); 
} 

Ausgang:

bei ConsoleApplicationN.exe.Program.Main (IL-Offset : 0x7)
bei ConsoleApplicationN.exe.Program.ThrowError (IL-Offset: 0x1b)
bei mscorlib.dll.DateTime..ctor (IL-Offset: 0x9)
bei mscorlib.dll.Da teTime.DateToTicks (IL-Offset: 0x61)
Nachricht: Die Parameter Year, Month und Day beschreiben eine nicht darstellbare DateTime.

können Sie dann Reflector oder ILSpy verwenden den Offset zu interpretieren:

.method private hidebysig static void ThrowError() cil managed 
{ 
    .maxstack 4 
    .locals init (
     [0] valuetype [mscorlib]System.DateTime myDateTime) 
    L_0000: nop 
    L_0001: ldloca.s myDateTime 
    L_0003: initobj [mscorlib]System.DateTime 
    L_0009: ldloca.s myDateTime 
    L_000b: ldc.i4 0x7d0 
    L_0010: ldc.i4 0x54c563 
    L_0015: ldc.i4.1 
    L_0016: call instance void [mscorlib]System.DateTime::.ctor(int32, int32, int32) 
    L_001b: nop 
    L_001c: ldloca.s myDateTime 
    L_001e: constrained [mscorlib]System.DateTime 
    L_0024: callvirt instance string [mscorlib]System.Object::ToString() 
    L_0029: call void [mscorlib]System.Console::WriteLine(string) 
    L_002e: nop 
    L_002f: ret 
} 

Sie wissen, dass die Anweisung vor 0x1b die Ausnahme ausgelöst hat. Es ist einfach, die C# -Code für das zu finden:

myDateTime = new DateTime(2000, 5555555, 1); 

Sie könnten den IL-Code in Ihrer C# -Code Karte jetzt, aber ich denke, die Verstärkung zu wenig wäre, und der Aufwand zu groß (obwohl es vielleicht ein Reflektor sein Plugin). Sie sollten mit dem IL-Offset in Ordnung sein.

+0

Ich mag Ihre Idee und upvoted Ihre Antwort, aber das ist nur eine Idee. Vielleicht gibt es eine Methode oder Informationen darüber, wie dieser IL-Versatz der entsprechenden PDB-Datei zugeordnet wird (da es viele Assemblys im Projekt gibt und jede Assembly über eine eigene PDB verfügt). – arbiter

+0

Es wäre wahrscheinlich das Beste, wenn Sie nur eine weitere Frage zum IL-Code zu den PDB-Dateien oder dem C# -Code zuordnen würden. Obwohl ich, wie gesagt, nicht sicher bin, ob das einfacher ist als nur manuell. – weiqure

+0

Für Watch-Fenster: neue System.Diagnostics.StackTrace ($ Ausnahme) .GetFrames() [0] .ILOffset – zproxy

1

Sie sind absolut auf dem richtigen Weg, PDB-Dateien zu benötigen, um Quellen- und Zeileninformationen genau zu erhalten. Ich würde alle wahrgenommenen Probleme mit dem Versand von PDB-Dateien in Frage stellen, da es sich tatsächlich um ein berechtigtes Anliegen handelt. Wenn jedoch ein berechtigter Grund vorliegt, können Sie dies tun, aber es erfordert mehr Aufwand, die entsprechende Software-Build-Umgebung zu erstellen.

Microsoft Symbol Server indiziert die Debugsymbole und speichert sie für die Verwendung zu einem späteren Zeitpunkt, wenn Sie beispielsweise einen Absturzspeicherauszug haben und Symbole benötigen. Sie können entweder Visual Studio oder Windbg auf Ihre eigene Symbolserverinstanz verweisen, genau wie Microsoft's, und es werden die für das Debuggen dieser Version Ihrer Anwendung erforderlichen Symbole abgerufen (vorausgesetzt, Sie haben die Symbole vor dem Versand mit Symbolserver indiziert).

Sobald Sie die entsprechenden Symbole für einen Build haben, müssen Sie sicherstellen, dass Sie die entsprechenden Quelldateien haben, die zum Build gehören.

Dies ist, wo Microsoft Source Server kommt. Genau wie in dem Symbol Server-Indizes Symbole, Quellserver wird Index Quelle um sicherzustellen, dass Sie die entsprechende Version des Quellcodes haben zu einem Software-Build gehört.

Arbeits Versionen von Version Control, Symbol Server und Quellserver sollten Teil Ihrer Software Configuration Management-Strategie sein.

Es gibt Third-Party-Tools, einige kommerziell, die Ihnen eine API zum Generieren von Anwendungs-Snapshots bieten, aber wie Sie bereits wissen, benötigen Sie einen Mechanismus, um diese Snapshots irgendwie in Ihre Umgebung zu bekommen.

John Robbins auf PDB Files

John Robbins auf Source Server

Check out WinDbg documentation auf ein Symbol Server zum Laufen.

Verwandte Themen