Frage bzgl. Exception (Wurfpunkt)



  • Hallo,

    diesmal im außerberuflichen Einsatz,
    und zwar schreibe ich aktuell an einem eigenen Exception Handler bzw. so würd ichs nicht nenne, eher so eine Art andere Exceptionausgabe und Logging.

    Vorgestellt hab ich mir das so, dass ich es dann nicht über eine messageBox ausgebe, sondern an eine eigene Klasse, welche die Ausgabe übernimmt und welche auch den Log erstellt.

    Ja ich weis, dass es schon einige fertige Klassen gibt, zb. bei mycsharp.de aber ich wollt etwas eigenes entwerfen, was ich in meinen ganzen privaten Projekten verwende.

    Nun zur eigentlichen Frage, wenn ich die Exception Global abfangen würde (fände ich an der Stelle einfach am besten), gibt es eine möglichkeit die methode in der die Exception gewurfen wurde heraus zu finden?



  • Exeption.StackTrace?



  • inflames2k schrieb:

    Nun zur eigentlichen Frage, wenn ich die Exception Global abfangen würde (fände ich an der Stelle einfach am besten), gibt es eine möglichkeit die methode in der die Exception gewurfen wurde heraus zu finden?

    ein bischen Copy&Paste

    String^ Logging2::CallingClass()
    {
    	StackFrame^ sf = GetStackFrame();
    
    	if (!sf) return L"System";
    	if (!sf->GetMethod()) return L"System";
    	if (!sf->GetMethod()->DeclaringType) return L"System";
    
    	String ^name = sf->GetMethod()->DeclaringType->Name;
    	return name;
    }
    String^ Logging2::CallingMethod()
    {
    	String^ delimiter = L" ()";
    	StackFrame^ sf = GetStackFrame();
    
    	if (!sf) return L"log()";
    
    	cli::array<String^>^ method = sf->GetMethod()->ToString()->Split(delimiter->ToCharArray());
    	return method[1];
    }
    void Logging2::CallingParameter()
    {
    	StackFrame^ sf = GetStackFrame();
    	if (!sf) return;
    
    	// im Gegensatz zu CallingMethod & CallingClass werden hier die Daten gleich mit geschrieben
    	cli::array<ParameterInfo^>^ pi = sf->GetMethod()->GetParameters();
    
    	for(int i = 0; i < pi->Length; i++)
    	{
    		String^ msg = String::Concat(L" -> ", pi[i]->Name, L" (",pi[i]->ParameterType->ToString());
    		msg = String::Concat(msg, L") = { ", L"n/a", L" }");  // TODO
    		writemsg(msg);
    	}
    }
    StackFrame^ Logging2::GetStackFrame()
    {
    	StackTrace^ strace = gcnew StackTrace(true);
    	String^ delimiter = " ()";
    	cli::array<String^>^ logtext;
    	int tracedepth = 1;			// 0 liefert GetStackFrame() ^^ ... spart etwas Rechenzeit
    
    	while(true)
    	{
    		bool ignore = false;
    
    		// Trace splitten
    		logtext = strace->GetFrame(tracedepth)->ToString()->Split(delimiter->ToCharArray());
    
    		// schauen ob die Methode ignoriert werden soll ... damit kann dann auch viewHex etc. ausgeblendet werden
    		for(int i = 0; i < TraceIgnoreMethod->Length; i++) if (!logtext[0]->ToLower()->CompareTo(TraceIgnoreMethod[i]->ToLower())) ignore = true;
    
    		// wenn die Methode nicht ignoriert werden darf
    		if (!ignore) break;
    
    		// ansonsten weiter suchen und hochzählen
    		tracedepth++;
    		if (tracedepth > strace->FrameCount) return nullptr;	// beenden wenn der Stack durch ist
    	}
    
    	// und StackFrame zurück
    	return strace->GetFrame(tracedepth);
    }
    

    als Tausch kannst Du Dich ja mal um das TODO kümmern 😉

    hand, mogel

    PS: ist kein C# ich weis - aber .NET 🤡



  • Naja der Stacktrace gibt ja noch so einiges anderes aus. Dachte nur, dass eventuell irgendwie direkt ran zu kommen ist.

    Der Stacktrace gibt ja Beispielsweise folgendes aus:

    bei System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
    bei System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
    bei System.Convert.ToInt32(String value)
    bei ExceptionTestForm.Form1.button1_Click(Object sender, EventArgs e) in H:\Projects\ExceptionTest\ExceptionTestForm\Form1.cs:Zeile 21.
    bei System.Windows.Forms.Control.OnClick(EventArgs e)
    bei System.Windows.Forms.Button.OnClick(EventArgs e)
    bei System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
    bei System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
    bei System.Windows.Forms.Control.WndProc(Message& m)
    bei System.Windows.Forms.ButtonBase.WndProc(Message& m)
    bei System.Windows.Forms.Button.WndProc(Message& m)
    bei System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
    bei System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
    bei System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

    Dass es dort mit vorhanden ist weis ich auch. - Sehs ja schon beim flüchtig drüber schaun.

    Huch seh ja grad da hat mir ja einer zugearbeitet. 🙂 Danke.

    Wie meinst du das mit dem TODO? 🙂



  • Hallo mogel, hab mit deinem Ansatz eine kürzere Variante erstellt, die soweit schoneinmal funktioniert.

    Da ich an die Instanz des Exceptionmanagers den Anwendungstitel mitgebe, prüfe ich den Stacktrace nur noch darauf, ob der Anwendungstitel im DeclaringType.FullName vorkommt.

    Sollte es der fall sein, setze ich nun auf 3 member-Variablen jeweils die aufrufende Klasse, die methode sowie die Zeilennummer.

    private void getInfos()
    		{
    			List<StackFrame> lstsf = new List<StackFrame>();
    			StackTrace st = new StackTrace( this.thrownException.Exception, true );
    			lstsf.AddRange( st.GetFrames() );
    			foreach (StackFrame sf in lstsf)
    			{
    				if (sf.GetMethod().ReflectedType.FullName.Contains( this.title ))
    				{
    					this.thrownMethod = sf.GetMethod().Name;
    					this.thrownFile = sf.GetMethod().DeclaringType.Name;
    					this.thrownLine = sf.GetFileLineNumber().ToString();					
    				}
    			}			
    		}
    

    // Hab mich da wohl zu früh gefreut.

    Wenn ich die Schleife nun nach dem ersten Treffer mittels break; verlasse stimmt es.



  • Wieso rufst du nicht einfach Exception.ToString() auf? Da ist der ganze Callstack ja schon hübsch formatiert mit drinnen...
    😕

    Sich selbst irgendwie durch den Callstack zu wühlen, macht wohl nur Sinn, wenn man sehr spezielle Anforderungen hat. z.B. dass man ihn (warum auch immer) als XML formatieren möchte, oder Zeilenweise in einer Datenbank speichern oder etwas in der Art.



  • Ich möchte aber wie bereits gesagt, ein Log erstellen in dem alle Exceptions die aufgetreten sind gespeichert werden.

    Das Log soll die Exception an sich beinhalten, den StackTrace, den Typ der Exception, die Klasse, die methode und die Zeile in der die Exception verursacht wurde.

    Einfach um hinterher schneller den Fehler lokalisieren zu können.

    Ich komme doch nun an alle benötigten Informationen.

    // Edit

    Was haltet ihr für sinnvoller? Abspeichern des Logs als reine Textdatei oder in XML?



  • hustbaer schrieb:

    Sich selbst irgendwie durch den Callstack zu wühlen, macht wohl nur Sinn, wenn man sehr spezielle Anforderungen hat. z.B. dass man ihn (warum auch immer) als XML formatieren möchte, oder Zeilenweise in einer Datenbank speichern oder etwas in der Art.

    bei mir ist es ebenfalls ein Logfile ... allerdings rufe ich den StackFrame nicht bei einer Exception auf sondern über eine Log-Meldung ... um zusehen welche Klasse bzw. Methode das ist ... zusätzlich kommen da noch Datum & Zeit sowie der Thread in die Zeile

    inflames2k schrieb:

    Was haltet ihr für sinnvoller? Abspeichern des Logs als reine Textdatei oder in XML?

    wenn Du es nur zum nachschauen benutzt, dann ist wohl Text am besten ... da kannst Du es gleich mit Notepad betrachten ... jede Exception eine Zeile mit allen Informationen

    Datum Zeit Klasse Zeile Exception.Message
    

    falls Du es später doch noch als XML brauchst kannst Du es ja parsen bzw. konvertieren

    hand, mogel



  • Ich werd mich wohl doch für XML entscheiden, da mir dort die Vorteile überwiegen.

    Immerhin ist es zum einen bei großen Dateien übersichtlicher & zum anderen einfacher zu handhaben.

    Bin mir noch nicht sicher, werde aber denk ich folgendes XML Schema wählen:

    <xml version="1.0">
      <Exceptions>
         <singleException>
             <DateTime>XX.XX.XXX - XX:XX</DateTime>
             <Message>Lorem ipsum dolor sit Amet...</Message>
             <Type>Exceptiontyp</Type>
             <StackTrace>xxxxxxxxxxxxxxxxxxxxxxxxx
                         xxxxxxxxxxxxxxxxxxxxxxxxx
             </StackTrace>
             <Class>Klassenname</Class>
             <Method>Methodenname</Method>
             <Line>Zeilennummer</Line>
         </singleException>
      </Exceptions>
    


  • Ich hab mir überlegt, dass ich die DLL wenn sie fertig ist, auch im release drin lasse.

    Grund dafür ist, dass sollte eine nicht behandelte Exception geworfen werden (an die man beim Entwickeln nicht gedacht hat & welche beim Betatest nicht auffiel), dass der Endbenutzer dann per Copy Button den Log-Text der aktuellen Exception kopieren kann und dann im Forum des Entwicklers seine Fehlerbeschreibung abgeben kann und außerdem den Logeintrag dazu posten kann.

    So kann der Fehler denk ich am ehesten gefixt werden.

    Hier mal 2 Screenshots vom Exception Fenster:

    Eigentliche Exception:
    http://www.myimg.de/?img=screenErrorReportc7dd7.gif

    Exception Log:
    http://www.myimg.de/?img=screenErrorReportLog8d181.gif

    Wollt anbei mal fragen, was ihr davon haltet, und ob es Übersichtlich genug ist. 🙂



  • ich finds gut und übersichtlich 👍



  • ja ... aber wenn der Benutzer schon auf einer Webseite den Text eintragen kann - wieso nicht gleich ein automatischen Upload ?



  • wäre eine Idee jedoch mit Einverständniserklärung vorher



  • Das ist allerdings auch eine Idee. Sogar eine Prima Idee wie ich finde. - Werds noch mit einbauen. - Aber nicht heut *g*

    Die Einverständniserklärung find ich wäre recht simple Lösbar, einfach unten noch einen Button hin "Fehlerbericht senden". - Wenn der Benutzer diesen klickt, muss er ja damit einverstanden sein.

    Allerdings werd ich dann noch ein extra Eingabefeld hinzufügen, wo der Benutzer selbst noch eintragen kann was er genau gemacht hat.

    Nun ist nur die Frage, lasse ich das ganze Logfile hochladen, oder nur die Exception die gerade geworfen wurde?



  • Für sowas würde sich wohl ein Minidump besser eignen, oder?


Anmelden zum Antworten