December 03, 2020, 07:49:01 PM

Author Topic: [bb] Save debugging messages to a debuglog file by Zethrax [ 1+ years ago ]  (Read 484 times)

Offline BlitzBot

  • Jr. Member
  • **
  • Posts: 1
Title : Save debugging messages to a debuglog file
Author : Zethrax
Posted : 1+ years ago

Description : *** Blitz3D Code ***
------------------------------------------------------------------------------------------------------------------------
The version below actively saves the debuglog message data to a file.
This may slow down your program due to the file accesses (depending on file caching). Or it may not. Ideally the file save would be done in a thread but that option doesn't exist in vanilla Blitz3D code.
This version is useful if you want to save data as it's aquired - potentially before a program crash that may prevent stored data from not being explicitely saved.
------------------------------------------------------------------------------------------------------------------------
You can use the 'DebugMsg' function  below to save debug messages to a debuglog file while your program is running.

An optional 'name' string and separator string can be added before the value.
== FUNCTIONS ==

DebugMsg( value$, name$ = "" )
*  Writes the specified 'value$' to the debuglog file. If the optional 'name$' is also specified then it will precede the 'value$' with a separator string between the pair.
*  If the debuglog file is not already open then a new file will be created automatically. If the file creation fails then the program will end with an error message.
*  By default the debuglog file will be a relative file named "debuglog.txt", but you can change this using the 'SetDebuglogFilepath' function.
*  By default the name-value separator will be a " = " string, but you can change this using the 'SetDebuglogSeparator' function.
SetDebuglogFilepath( filepath$ )
*  Sets a different filename and relative or absolute filepath for the debuglog file.
*  This function is optional. By default "debuglog.txt" is used for the filepath.
SetDebuglogSeparator( separator$ )
*  Sets a different separator string to use between name and value pairs.
*  This function is optional. By default " = " is used for the separator.
CloseDebuglog()
*  If an open debuglog file exists then this function will close it.
*  You can also use it to close an existing debuglog file and then start writing to a new one (the old one will be overwritten if you don't use 'SetDebuglogFilepath' to change the filepath).
*  This function can be safely called even if no debuglog file exists.
*  Note that all files are closed automatically when a Blitz program ends so this is somewhat redundant, but it's here if you need it.
Code: [Select]
Global G_debuglog_filepath$ = "debuglog.txt"
Global G_debuglog_separator$ = " = "
Global G_debuglog_file



Function SetDebuglogFilepath( filepath$ )
; Sets a different filename and relative or absolute filepath for the debuglog file.
; This function is optional. By default "debuglog.txt" is used for the filepath.

G_debuglog_filepath$ = filepath$
End Function



Function SetDebuglogSeparator( separator$ )
; Sets a different separator string to use between name and value pairs.
; This function is optional. By default " = " is used for the separator.

G_debuglog_separator$ = separator
End Function



Function CloseDebuglog()
; If an open debuglog file exists then this function will close it.
; You can also use it to close an existing debuglog file and then start writing to a new one (the old one will be overwritten if you don't use 'SetDebuglogFilepath' to change the filepath).
; This function can be safely called even if no debuglog file exists.
; Note that all files are closed automatically when a Blitz program ends so this is somewhat redundant, but it's here if you need it.

If G_debuglog_file Then CloseFile G_debuglog_file : G_debuglog_file = 0
End Function



Function DebugMsg( value$, name$ = "" )
; Writes the specified 'value$' to the debuglog file. If the optional 'name$' is also specified then it will precede the 'value$' with a separator string between the pair.
; If the debuglog file is not already open then a new file will be created automatically. If the file creation fails then the program will end with an error message.
; By default the debuglog file will be a relative file named "debuglog.txt", but you can change this using the 'SetDebuglogFilepath' function.
; By default the name-value separator will be a " = " string, but you can change this using the 'SetDebuglogSeparator' function.


If G_debuglog_file ; If an open debuglog file exists...
If name$ <> "" Then value$ = name$ + G_debuglog_separator$ + value$ ; If the name was supplied then add the name before the value with a separator between them.
Else ; No open debuglog file exists, so let's create one.
G_debuglog_file = WriteFile( G_debuglog_filepath$ ) ; Attempt to create the file.
If G_debuglog_file ; If the file was created successfully...
If name$ <> "" Then value$ = name$ + G_debuglog_separator$ + value$ ; If the name was supplied then add the name before the value with a separator between them.
Else ; The file creation failed, so end the program with an error message.
RuntimeError "Unable to create the debuglog file: " + G_debuglog_filepath$
EndIf
EndIf
; At this point either the file will exist or the program will have ended with an error message.
WriteLine G_debuglog_file, value$ ; Write the value to the file.
End Function



; === EXAMPLE USAGE ===



; *** Make sure you have this file saved someplace before running this example code. If you run it as a temp file then the debuglog file will likely end up somewhere unexpected.



Dim arr$( 5 ) : arr$( 1 ) = "One" : arr$( 2 ) = "Two" : arr$( 3 ) = "Three" : arr$( 4 ) = "Four" : arr$( 5 ) = "Five"

;SetDebuglogFilepath( "my_debuglog.txt" ) ; Optional. Filepath defaults to "debuglog.txt".

;SetDebuglogSeparator( ": " ) ; Optional. Separator string defaults to " = ".

For i = 1 To 5 : DebugMsg( i, arr$( i ) ) : Next

CloseDebuglog() ; Close the debuglog file. Note that all open files are closed automatically when a Blitz program ends so this is somewhat redundant.

Print "The debug data has been saved." : Print "Press any key to exit." : WaitKey : End



------------------------------------------------------------------------------------------------------------------------
The version below stores the data in a type list and then saves it to a file when 'SaveDebuglog' is called.
This is the most efficient way to handle the data, but the downside to this is that the data won't be saved if a crash prevents 'SaveDebuglog' from being executed.
If you want to actively save the data then see the version above this one.
------------------------------------------------------------------------------------------------------------------------
You can use the 'DebugMsg' function  below to save debug messages to a debuglog file while your program is running.

An optional 'name' string and separator string can be added before the value.

The data is temporarily stored in a type list. Use 'SaveDebuglog' at the end of your program to save the data to a file.

If there are no debug messages to save then nothing is saved and no files are created or updated.
== FUNCTIONS ==

DebugMsg( value$, name$ = "" )
*  Writes the specified 'value$' to the debuglog list.
*  If the optional 'name$' is also specified then it will precede the 'value$' in the saved file with a separator string between the pair.
ClearDebugList()
*  Clears the list of debuglog messages.
*  You can use this command to clear out the list to allow you to start a new list mid-program.
SaveDebuglog( filepath$ = "", separator$ = "", do_append = False )
*  Saves the debuglog data to the specified 'filepath$'. Normally you'll want to add this at the end of your program.
*  If there are no debug messages to save then nothing is saved and no files are created or updated.
*  The 'filepath$' parameter is optional. If it is omitted or a blank string supplied then the file will be saved as a relative file named "debuglog.txt".
*  A 'separator$' string can optionally be specified to separate the name and value pairs (assuming the 'name' string was supplied via 'DebugMsg').
*  If the 'separator$' string is omitted or a blank string supplied then the default " = " separator string will be used if needed.
*  If the 'do_append' flag is set to True (defaults to False) then the data will be appended to any existing file at the specified 'filepath$'. If no file exists at that filepath then a new file will be created.
Code: [Select]
Type T_debuglog
Field value$
Field name$
End Type



Function DebugMsg( value$, name$ = "" )
; Writes the specified 'value$' to the debuglog list.
; If the optional 'name$' is also specified then it will precede the 'value$' in the saved file with a separator string between the pair.

entry.T_debuglog = New T_debuglog
entryvalue$ = value$
entry
ame$ = name$
End Function



Function ClearDebugList()
; Clears the list of debuglog messages.
; You can use this command to clear out the list to allow you to start a new list mid-program.

Delete Each T_debuglog
End Function



Function SaveDebuglog( filepath$ = "", separator$ = "", do_append = False )
; Saves the debuglog data to the specified 'filepath$'. Normally you'll want to add this at the end of your program.
; If there are no debug messages to save then nothing is saved and no files are created or updated.
; The 'filepath$' parameter is optional. If it is omitted or a blank string supplied then the file will be saved as a relative file named "debuglog.txt".
; A 'separator$' string can optionally be specified to separate the name and value pairs (assuming the 'name' string was supplied via 'DebugMsg').
; If the 'separator$' string is omitted or a blank string supplied then the default " = " separator string will be used if needed.
; If the 'do_append' flag is set to True (defaults to False) then the data will be appended to any existing file at the specified 'filepath$'. If no file exists at that filepath then a new file will be created.

; - Count the number of items on the list.
For entry.T_debuglog = Each T_debuglog
n = n + 1
Next

If n = 0 Then Return ; If there are no items on the list then abort without saving anything.

If filepath$ = "" Then filepath$ = "debuglog.txt"
If separator$ = "" Then separator$ = " = "

If do_append
; Attempt to open the file, or create a new one if the file does not exist.
file = OpenFile( filepath$ ) ; Attempt to open the file.
If file ; If the file exists then prepare it to be appended to.
SeekFile ( file, FileSize( filepath$ ) )
Else
If FileType( filepath$ ) = 0 Then file = WriteFile( filepath$ ) ; If the file didn't exist then attempt to create the file.
EndIf
Else
file = WriteFile( filepath$ ) ; Attempt to create the file.
EndIf

If file ; If the file was created successfully...
For entry.T_debuglog = Each T_debuglog
value$ = entryvalue$
If entry
ame$ <> "" Then value$ = entry
ame$ + separator$ + value$ ; If the name was supplied then add the name before the value with a separator between them.
WriteLine file, value$ ; Write the value to the file.
Next
CloseFile file
Else ; The file creation failed, so end the program with an error message.
RuntimeError "Unable to open or create the debuglog file: " + filepath$
EndIf
End Function



; === EXAMPLE USAGE ===



; *** Make sure you have this file saved someplace before running this example code. If you run it as a temp file then the debuglog file will likely end up somewhere unexpected.



Dim arr$( 10 )
arr$( 1 ) = "One" : arr$( 2 ) = "Two" : arr$( 3 ) = "Three" : arr$( 4 ) = "Four" : arr$( 5 ) = "Five"
arr$( 6 ) = "Six" : arr$( 7 ) = "Seven" : arr$( 8 ) = "Eight" : arr$( 9 ) = "Nine" : arr$( 10 ) = "Ten"

For i = 1 To 5 : DebugMsg( i, arr$( i ) ) : Next

SaveDebuglog ; Save the debuglog list to a new file with the default "debuglog.txt" filename.

ClearDebugList() ; Clear the debug list.

For i = 6 To 10 : DebugMsg( i, arr$( i ) ) : Next

SaveDebuglog( "", "", True ) ; Append the debuglog list to an existing file.

Print "The debug data has been saved." : Print "Press any key to exit." : WaitKey : End


Code :
Code: BlitzBasic
  1. The code can be found at: http://www.blitzbasic.com/codearcs/codearcs.php?code=3181


Comments :


degac(Posted 1+ years ago)

 Hitechnically a debuglog *should* write immediately any message (so default is append mode in your function), because in case of break-up you are not sure if your application can save the info before 'closing'...I have implemented (for Bmax) my own Debullog function: each message I 'write' (PrintLog) is immediately saved on a file.


Matty(Posted 1+ years ago)

 Yep.  A debug log that writes nothing on program crash is not too useful.  Having an append mode is pretty important.


Zethrax(Posted 1+ years ago)

 Ok I've swapped the two versions so that the version that saves the debuglog messages directly to the debuglog file appears first. This version will effectively append the messages to the file as soon as they are received.Since Blitz3D in debug mode closes all files on a soft crash, the file-system's file cache should get saved correctly in the event of a crash. That's my understanding anyway (I did some quick testing that seemed to confirm this).Any hard crashes that happen outside the protection of the debugger are outside the scope of my little code-lib, of course.


 

SimplePortal 2.3.6 © 2008-2014, SimplePortal