Debugging Tools

Back to index


Debug Log

OOFILE 1.3b2d15 adds the ability to define a log file name and have most database actions logged. This is extremely useful when tracking down bugs with changes of state, particularly things like the database being unexpectedly in a different sort order.

Warning: the logs can grow very quickly. In particular a GUI application will generate a lot of entries as the rows are displayed in database browsers. Logs of several hundred kb are common.

Debug logging will also slow you down, but not as much as a memory debugger like SmartHeap™ or Spotlight™.

Debug logging may help you identify unnecessary database operations, as well as outright bugs.

Enabling debug logging

Add a
#define OOF_DEBUG_LOG_NAME "oof.debuglog"
as a global define for your project. It may be worth keeping a separate build with logging, to avoid recompiling all files.

"oof.debuglog" is just a name chosen for this example. You can choose any name you like that's a legal file name. The test of logging being enabled is #ifdef OOF_DEBUG_LOG_NAME.

Writing your own entries to the log

OOF_DEBUG_LOG is always defined and calls dbConnect::logComment which takes either a const char* or ostream& param.

Therefore you can embed calls like
OOF_DEBUG_LOG("Entering XXX about to save");
throughout your code and they will compile out if you don't define OOF_DEBUG_LOG_NAME.

Debugging tactics with the log

The log is opened and closed with each entry, to guarantee file writing. This is also useful if you want to get a small log for a given area of code, whilst running the debugger.

Sample log entries

dbBrowseHelper::selectRecNo	0	on table	1124010
 
dbBrowseHelper::selectRecNo	0	on table	1124238
 
dbTable::cloneWithoutSelection()
table: Q	111dcb0	(valid)	Connection: 10fca80
RecState: eUnloaded	Offset: 0	Clean	Iter: 0	State: allRecs
 
 
dbTable::setTableValid(true)
table: Q	11c20d8	(valid)	Connection: 10fca80
RecState: eUnloaded	Offset: 0	Clean	Iter: 0	State: empty
 
 
dbTable::start()
table: P	110a2e8	(valid)	Connection: 10fca80
RecState: eUnloaded	Offset: 0	Clean	Iter: 0	State: allRecs
 
 
dbTable::ContextChange() - requireExplicit
table: P	110a2e8	(valid)	Connection: 10fca80
RecState: eUnloaded	Offset: 0	Clean	Iter: 0	State: allRecs
 
 
dbSorter::sortNow	10fdbb0	sorting: P (110a2e8)
 
dbTable::cloneWithoutSelection()
table: P	110a2e8	(valid)	Connection: 10fca80
RecState: eUnloaded	Offset: 0	Clean	Iter: 0	State: allRecs
 
 
dbTable::setTableValid(true)
table: P	11c9348	(valid)	Connection: 10fca80
RecState: eUnloaded	Offset: 0	Clean	Iter: 0	State: empty
 
 
selectJustRecordPointer(313018)table: P	11c9348	(valid)	Connection: 10fca80
RecState: eUnloaded	Offset: 0	Clean	Iter: 0	State: empty
 


SmartHeap

If you use MicroQuill's SmartHeap product then defining OOF_SmartHeap will include smrtheap.hpp and perform pool validation at selected points to aid in detecting bugs such as memory overwrites. This runs a LOT slower but provides a high degree of assurance.

#define OOF_SmartHeap
#define MEM_DEBUG 1
#define DEFINE_NEW_MACRO 1


OVERVIEW of OOF_Debug

OOF_Debug is a #define flag, that will turn on debugging modes within OOFILE. These are in the nature of development-time checks and so you may not want them left in released applications! However, the errors they trigger will be handled by the standard error handler (dbConnect::raise), so you could theoretically cope with them yourself. Most of the OOF_Debug errors are programmer errors, and it should not be relied on as (say) a range-checking recovery mechanism.


OVERRUNS ON OOF_DICTIONARY

If you write to an unallocated cell that is more than one past the previous high point (ie: not just an append) then OOF_DictRep::operator[](long) will report the error. This catches problems such as incorrect copying of objects (mainly our mistakes) or scrambling memory so that the index being used on the dictionary is a ridiculous value.


RANGE ERRORS ON NUMERIC FIELDS

Conversion from a double to a long, or short and conversion from a long to a short are range-checked when the fields are assigned a value.


INAPPROPRIATE ACTIONS LOCKED

Attempting to add a record while read-locked will raise an error.

Attempts to set a read lock whilst write-locked and vice versa will raise an error, as will failing to match the number of ApplyLock calls to ReleaseLock's.


Back to index


(c) Copyright A.D. Software 1994-1997 (All Rights Reserved).
Last Updated: 8th March 1997