Hallo Community,
Ich habe mich gestern Abend mal ein wenig damit auseinandergesetzt, wie man Fehler und Ausnahmen in BlitzMax korrekt behandeln kann. Klar, Try/Catch nutzen etc.
Aber oftmals macht das Programm einfach weiter und man merkt nicht zwangsläufig, dass ein Feher gefangen wurde, außer höchstens durch Debuglog-Ausgaben.
Da hab ich mir gedacht: Es wäre doch ganz schick, wenn man in solchen (und ähnlichen Fällen) einfach eine Datei hätte, in die die gefangenen Ausnahmen oder aufgetretenen Fehler reingeschrieben werden können. Das ist ja auch hilfreich, wenn das Programm veröffentlicht wird, für Fehlerlogs die der Benutzer dann übermitteln kann.
Ums kurz zu machen: Heraus kam eine Klasse, die Fehler schön formatiert in eine Datei schreibt. Man kann auch mehrere Log-Dateien haben, nämlich pro Klasseninstanz eine.
Es gibt drei Möglichkeiten einen Fehler zu loggen:
- Eine gefangene Exception
- Ein Fehler, von dem man weiß, dass er auftreten kann, der aber nicht zwangsläufig zum Crash führt und für den man nicht unbedingt einen Try/Catch Block machen will
- Ein Fehler, in den man reinschreiben kann, was man will.
Hier ist die Klasse:
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN]
Type TErrorLogger Field _strLogFile:TStream Field _sLoggerName:String Field _iErrorNumber:Int Method LogFile:TStream() Return _strLogFile End Method Method SetLogFile(pstrLogFile:TStream) If(LogFile() <> Null) LogFile().Close() EndIf _strLogFile = pstrLogFile End Method Method SetNewLogFile(psFileName:String) If(LogFile() <> Null) LogFile().Close() EndIf _strLogFile = WriteStream(psFileName) End Method Method LoggerName:String() Return _sLoggerName End Method Method __SetLoggerName(psLogName:String) _sLoggerName = psLogName End Method Method ErrorNumber:Int() Return _iErrorNumber End Method Method __SetErrorNumber(piErrorNumb:Int) _iErrorNumber = piErrorNumb End Method Function Create:TErrorLogger(psFileName:String, psLogName:String) Local errorLogger:TErrorLogger = New TErrorLogger errorLogger.SetNewLogFile(psFileName) errorLogger.__SetLoggerName(psLogName) errorLogger.__SetErrorNumber(0) errorLogger.LogFile().WriteLine("Error File of Logger: " + errorLogger.LoggerName()) errorLogger.LogFile().WriteLine("") Return errorLogger End Function Method LogException(psMethodName:String, psClassName:String = "", psCustomText:String = "", .. pobjException:Object, piIsFunction:Int, pobjUsedObject:Object = Null) IncErrorNumber() LogFile().WriteLine("[CATCHED_EXCEPTION] Error No. " + ErrorNumber()) If(piIsFunction) Then LogFile().WriteLine(" -In Function: " + psMethodName) Else LogFile().WriteLine(" -In Method: " + psMethodName) EndIf If(psClassName <> "") Then LogFile().WriteLine(" -In Class: " + psClassName) EndIf If(pobjUsedObject <> Null) Then LogFile().WriteLine(" -By using Object: " + pobjUsedObject.ToString()) EndIf LogFile().WriteLine(" -ExceptionText: " + pobjException.ToString()) If(psCustomText <> "") Then LogFile().WriteLine(" -Custom Text: " + psCustomText) EndIf LogFile().WriteLine("") End Method Method LogError(psMethodName:String, psClassName:String = "", psErrorText:String, piIsFunction:Int, pobjUsedObject:Object = Null) IncErrorNumber() LogFile().WriteLine("[DETECTED_ERROR] Error No. " + ErrorNumber()) If(piIsFunction) Then LogFile().WriteLine(" -In Function: " + psMethodName) Else LogFile().WriteLine(" -In Method: " + psMethodName) EndIf If(psClassName <> "") Then LogFile().WriteLine(" -In Class: " + psClassName) EndIf If(pobjUsedObject <> Null) Then LogFile().WriteLine(" -By using Object: " + pobjUsedObject.ToString()) EndIf LogFile().WriteLine(" -Error Text: " + psErrorText) LogFile().WriteLine("") End Method Method LogCustomError(psErrorText:String) IncErrorNumber() LogFile().WriteLine("[DETECTED_ERROR] Error No. " + ErrorNumber()) LogFile().WriteLine(" -Error Text: " + psErrorText) LogFile().WriteLine("") End Method Method EndLogging() LogFile().WriteLine("Total Errors logged: " + ErrorNumber()) If(LogFile() <> Null) Then LogFile().Close() EndIf End Method Method IncErrorNumber() __SetErrorNumber(ErrorNumber() + 1) End Method End Type
Und natürlich gibts auch ein Beispielprogramm dazu:
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] Global ErrorLog:TErrorLogger = TErrorLogger.Create("Elogger.log", "Errors")
TPoint.Create(20.0, 30.0) TPoint.Create(30.0, 4.0) TPoint.Create(-10.0, 2.0)
TPoint.Init()
TPoint.Create(10.0, -2.0) TPoint.Create(-10.0, -2.0)
ErrorLog.LogCustomError("Sorry, no cake for you at " + CurrentDate())
ErrorLog.EndLogging()
Type TPoint Global tlAllPoints:TList Field fPosX:Float Field fPosY:Float Function Init() tlAllPoints = New TList End Function Function Create:TPoint(x:Float, y:Float) Local point:TPoint = New TPoint point.SetX(x) point.SetY(y) Try tlAllPoints.AddLast(point) Return point Catch ex:Object ErrorLog.LogException("Create", "TPoint", "Probably list not initialized.", ex, True, point) End Try End Function Method SetX(x:Float) fPosX = x If(x < 0) Then ErrorLog.LogError("SetX", "TPoint", "Point can't be drawn on screen: " + fPosX + " | " + fPosY, False, Self) EndIf End Method Method SetY(y:Float) fPosY = y If(y < 0) Then ErrorLog.LogError("SetY", "TPoint", "Point can't be drawn on screen: " + fPosX + " | " + fPosY, False, Self) EndIf End Method End Type
Die Datei, die das Programm schreibt sieht dann so aus:
Zitat:Error File of Logger: Errors
[CATCHED_EXCEPTION] Error No. 1
-In Function: Create
-In Class: TPoint
-By using Object: 0232EBB0
-ExceptionText: Attempt to access field or method of Null object
-Custom Text: Probably list not initialized.
[CATCHED_EXCEPTION] Error No. 2
-In Function: Create
-In Class: TPoint
-By using Object: 0232F1E0
-ExceptionText: Attempt to access field or method of Null object
-Custom Text: Probably list not initialized.
[DETECTED_ERROR] Error No. 3
-In Method: SetX
-In Class: TPoint
-By using Object: 0232F570
-Error Text: Point can't be drawn on screen: -10.0000000 | 0.000000000
[CATCHED_EXCEPTION] Error No. 4
-In Function: Create
-In Class: TPoint
-By using Object: 0232F570
-ExceptionText: Attempt to access field or method of Null object
-Custom Text: Probably list not initialized.
[DETECTED_ERROR] Error No. 5
-In Method: SetY
-In Class: TPoint
-By using Object: 0232FC40
-Error Text: Point can't be drawn on screen: 10.0000000 | -2.00000000
[DETECTED_ERROR] Error No. 6
-In Method: SetX
-In Class: TPoint
-By using Object: 023300B0
-Error Text: Point can't be drawn on screen: -10.0000000 | 0.000000000
[DETECTED_ERROR] Error No. 7
-In Method: SetY
-In Class: TPoint
-By using Object: 023300B0
-Error Text: Point can't be drawn on screen: -10.0000000 | -2.00000000
[DETECTED_ERROR] Error No. 8
-Error Text: Sorry, no cake for you at 01 Mar 2012
Total Errors logged: 8
Dort sieht man dann, warum man in den LogFunktionen wahlweise eine Instanz des gerade benutzten Objekts mitgeben kann: Man sieht im Log nacher, ob das gleiche Objekt öfter Fehler verursacht hat.
So, falls es noch Fragen, Anregungen oder ähnliches gibt, dann schreibt einfach.
Lg, M0rgenstern
|