Debugging Your Web Application
To Debug Or Not To Debug
The first thing to decide is what areas of your application you wish to debug. The areas this web site is capable of recording are:
- Query errors (e.g. invalid SQL)
- Select statements
- Delete statements
- Update statements
- Insert statements
- Cache reads
- Cache writes
- Cache cleans
- Amazon Product requests
In a production environment, it would be unwise to debug all of these - imagine how large your log file would be if every single SQL statement was logged. That is why I only debug errors for the live version of the site.
I sometimes record all other SQL queries in development just to get an idea of all queries being executed and looking for possible improvements or optimizations.
This site uses Amazon to fetch the data about books and publications – sometimes errors occur and we also track these.
Next, we need to turn each of these different debugging areas into code. We use defines for this, as the values never need to change and they are easily available in the global scope. It also gives us a human-readable name for the debug level.
We refer to each define as a “switch” (think of it like a lightswitch, if the switch is off we’re not debugging that section, if it’s on, we are).
Each switch value must be a power of two – this lets us turn on any or all of the switches (we’ll get to that later).
Another good practice is to prefix each switch with
DEBUG_, and then within that name for the area they relate to (e.g. all SQL related switches would begin with
This code should be placed in a globals file (or some file that is visible to all other PHP scripts in your application).
define('DEBUG_SQL_SELECT' , 1); define('DEBUG_SQL_INSERT' , 2); define('DEBUG_SQL_UPDATE' , 4); define('DEBUG_SQL_DELETE' , 8); define('DEBUG_SQL_ERROR' , 16); define('DEBUG_CACHE_GET' , 32); define('DEBUG_CACHE_SAVE' , 64); define('DEBUG_CACHE_CLEAN', 128); define('DEBUG_AMAZON' , 256); define('DEBUG_AMAZON_ERROR', 512);
We can also make a few other switches just to make our lives a bit easier, such as one for no debugging, one to debugging everything, or one to debug say, anything SQL related.
To do this, we use the bitwise ‘OR’ operator so combine the values.
Note: rather than specifying every level explicitly for our
DEBUG_ALL flag, just pick a high power of 2 and then subtract 1, this ensures all the bits are “switched on”.
define('DEBUG_NONE', 0); define('DEBUG_ALL', 65535); define('DEBUG_SQL_ALL', DEBUG_SQL_SELECT | DEBUG_SQL_INSERT | DEBUG_SQL_UPDATE | DEBUG_SQL_DELETE | DEBUG_SQL_ERROR); define('DEBUG_CACHE_ALL', DEBUG_CACHE_GET | DEBUG_CACHE_SAVE | DEBUG_CACHE_CLEAN); define('DEBUG_AMAZON_ALL', DEBUG_AMAZON | DEBUG_AMAZON_ERROR);
This might be a little over the top, but you get the idea. You can also create other variations which may make your life easier.
define('DEBUG_ERRORS', DEBUG_SQL_ERROR | DEBUG_AMAZON_ERROR);
The other thing we have to define is what we actually want to debug.
This part works basically identically to PHP’s error reporting (see php.net/error_reporting)
Here are a few examples (note that there should only be one occurrence of defining the debug level):
// debug all errors define('DEBUG_LEVEL', DEBUG_ERRORS); // debug all SQL related stuff define('DEBUG_LEVEL', DEBUG_SQL_ALL); // debug cache gets and amazon errors define('DEBUG_LEVEL', DEBUG_CACHE_GET | DEBUG_AMAZON_ERROR); // debug all SQL except for select statements define('DEBUG_LEVEL', DEBUG_SQL_ALL & ~DEBUG_SQL_SELECT);
The bitwise operators can get a bit complicated. There’s a tutorial at the Java web site: Shift and logical operators