DebugX

For a while, I’ve had a simple little debug class that let’s me output messages to the debug window or to a text file. For example in my application that sends an email, if the sending fails for some reason, I create a little text file the user can send me:

if !oMail.Send()

local oDebug

oDebug = newobject(“DebugX”)

oDebug.Message(“Email Failed”)

oDebug.Message(“Email address was: ” + oMail.cSendTo)

oDebug.Message(“Error message was: ” + oMail.cErrorMsg)

endif

This class has a couple little interesting features:

  • As noted, the message function can send to the debug window or to a text file. Just set the .cOutputType property.
  • Every .Message() gets a date + time stamp so I know when it happens.
  • I know this never happens to you, but I sometimes forget to remove the debug code before sending to production. This class has a lIsDevelopement property. If it’s not developement, then the .Message() doesn’t do anything.

Tamar‘s talk about speeding up Foxpro code at Southwest Fox prompted me to add a couple new functions:

  • Added a .Start() and .Stop() to start/stop a timer. Any .Message() that is sent while the timer is going will include the elapsed seconds. This works correctly over Midnight as well.
  • Added a .Loop() function that will loop a .nLoop number of times. This is handy if one pass through your code is not enough to accurately time how long it takes. If you accidentally leave this code in for production, nLoop always resets to 1.

So you can do things like:

local oDebug

oDebug = newobject(“DebugX”)

oDebug.Message(“Debug Starting”)

oDebug.Start(“Start timing some code, Loop 4 times”)

oDebug.nLoop = 4

do while oDebug.Loop()

oDebug.Message(“Pass # ” + tran(oDebug.nLoop))

<some Foxpro code I want to time >

enddo

oDebug.Stop(“End of debugging test”)

Here’s the code:

* DebugX: Class for creating messages during debugging.
* Created 11/3/15 by Todd Landrum, todd@paladinpgm.com
* With thanks to:
* Tamar Granor – Who's speed talk at Southwest Fox 2015 inspired the Start, Stop and Loop functions.
* You can use this method to easily add messages to your code for debugging purposes.
* Messagbes can be sent to the debug window or a text file.
* It can be used in a number of ways.
* To just give messages in your code:
* DebugX.Message("This is some message")
* It has a timer built-in so you can get the time it took some code to run:
* DebugX.Start("My timer is starting")
* <some code>
* DebugX.End("The code has finished")
* It has a looping function built-in as well.
* DebugX.nLoop = 10
* do while DebugX.nLoop
* <some code>
* enddo
* IMPORTANT: There is a lIsDevelopement property. If this is .f., then no messages
* will be output and for a loop, it will always do it just once regardless of nLoop.
* This way if you leave this in your code by mistake, it won't hurt anything in production.
* The INIT method sets this property for me – you should override it!
DEFINE CLASS DebugX AS Custom
cOutputType = "Debug" && 'Debug' if you want messages to the debug output, else 'Text' for text file
cOutputTextFile = "Debug.txt" && Default name, change if you want.
lOutputEraseTextFile = .t. && First message should create a new text file, erasing any existing one.
lShowSeconds = .f. && Seconds are shown for each message, set to .t. if the .Start() method is called.
lIsDevelopment = .t. && Output will not happen if this is .f.
&& The init function sets this, you should override it.
tStartDateTime = {} && For the Start/Stop timer functions.
tEndDateTime = {}
nStartSeconds = 0
nEndSeconds = 0
nTotalSeconds = 0
nSecondsInDay = 86400
nLoop = 1 && Number of loops to perform
**************************
PROCEDURE Init()
* This is the code for me that determines if I'm
* on my development machine. You'd change this to
* something you want.
this.lIsDevelopment = FILE("w:\paladin.txt")
ENDPROC
**************************
FUNCTION Destroy()
ENDFUNC
**************************
FUNCTION Start()
PARAMETERS tMsg
IF EMPTY(tMsg)
tMsg = "Start"
ENDIF
this.tStartDateTime = DATETIME()
this.nStartSeconds = SECONDS()
this.lShowSeconds = .t.
this.Message(tMsg)
ENDFUNC
**************************
FUNCTION Stop()
PARAMETERS tMsg
IF EMPTY(tMsg)
tMsg = "Stop"
ENDIF
this.tEndDateTime = DATETIME()
this.nEndSeconds = SECONDS()
this.nTotalSeconds = this.CalcSeconds()
this.Message(tMsg)
this.lShowSeconds = .f.
ENDFUNC
**************************
FUNCTION CalcSeconds()
PARAMETERS nStartSeconds, nEndSeconds
IF EMPTY(nStartSeconds)
nStartSeconds = this.nStartSeconds
ENDIF
IF EMPTY(nEndSeconds)
nEndSeconds = this.nEndSeconds
ENDIF
* Adjust total seconds if we ran over midnight
LOCAL lDays, lSeconds
lDays = TTOD(DATETIME()) – TTOD(this.tStartDateTime)
lSeconds = nEndSeconds – nStartSeconds
IF lDays > 0
lSeconds = lSeconds + (lDays * this.nSecondsInADay)
ENDIF
RETURN lSeconds
ENDFUNC
**************************
FUNCTION Loop
IF !this.lIsDevelopment
this.nLoop = 1
ENDIF
LOCAL lReturn
lReturn = (this.nLoop > 0)
this.nLoop = this.nLoop – 1
RETURN lReturn
ENDFUNC
**************************
FUNCTION Message
PARAMETERS tMessage
* tMessage = Message to output
* tInit = Determines if a new text file should be created or append.
IF !this.lIsDevelopment
RETURN
ENDIF
LOCAL lMsg
lMsg = tMessage + " : " + TTOC(DATETIME())
IF this.lShowSeconds
lMsg = lMsg + ", Seconds Elapsed: " + tran(this.CalcSeconds(this.nStartSeconds, SECONDS()))
endif
IF this.cOutputType = "Debug"
DEBUGOUT lMsg
ELSE
IF this.lOutputEraseTextFile && First time, we want to create blank output file.
DELETE FILE (this.cOutputTextFile)
this.lOutputEraseTextFile = .f. && Don't erase output file anymore
ENDIF
* Get any existing output, append this onto it.
LOCAL lStr
IF FILE(this.cOutputTextFile)
lStr = FILETOSTR(this.cOutputTextFile)
lStr = lStr + CHR(13) + CHR(10)
else
lStr = ""
endif
STRTOFILE(lStr + lMsg, this.cOutputTextFile)
ENDIF
ENDFUNC
ENDDEFINE

view raw
DebugX
hosted with ❤ by GitHub

One thought on “DebugX

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s