How Do I Do An Error Handler?
There can be multiple components to an error handler, and it can either be used to protect a single template or an entire server's web sites -- the Site-Wide Error Handler you often hear spoken about in hushed tones. As error handling goes, you may want the same action run no matter what the error, or what the domain is that throws it. You may also want to perform different actions depending on the same or even more complex circumstances; for example based on what block of code blows up in a particular template.
We'll go over a system that has the flexibility to allow this, as well as being capable of implementation as an individual page error handling template that can even be customized to a degree for a particular application.
I'll say right away this system will not attempt to fix errors. If you've been working for any length of time in the client/server world of desktop applications you have no doubt built error handlers that 'heal' wounds caused by errant users, munged memory or just bad karma. You can do the same thing with ColdFusion, although it isn't often done.
Instead we'll simply attempt to recover from errors as gracefully as possible. We'll conceal all system details from the visitor and show them a 'friendly' error page. We'll also log detailed diagnostic information as needed, both to disk and -- if allowed -- via email to the designated administrator. Finally we will implement a secure error viewer for diagnostic information deemed too sensitive to transmit via email.
Creating a Multi-Site Handler Listing 1 shows errors.cfm, which is the parent template for our site-wide error handler. It decides what gets done on a domain-by-domain basis. The file is just a simple switch, with multiple cases for one or more domains as you see fit. You can run any ColdFusion code here that you please, but in this case all we are doing is setting up and running our diagnostic dump/save routine, and a friendly display screen that varies from domain to domain. In the second case we are just dumping data to the screen.
The dump/save routine requires three parameters:
variables.emailTo |
The sender of the notification email. |
variables.emailFrom |
The notification email recipient. |
variables.emailServer |
The mail server used to send the notification email. |
Note also the 'error display' includes at the tail end of two of the cases. No example of these is given as a listing. What you do here is set up a simple html page that matches either the subject site's domain... or doesn't deviate from it too much. On that page you put language apologizing for the inconvenience, coupled to links to the site's home page or whatever suits you.
DumpMonger.cfm Listing 2 is dumpmonger.cfm; the file that is the core of our error reporting system. Note that DumpMonger does not require an error condition to run. You can use it to dump out a boatload of information as you please during development if you like, for any reason you choose.
The first thing we do in DumpMonger is assign a default value to four variables. We might assign these values externally in some other template, too, but that depends on individual needs. For example these variables can be set at a point inside of a CF template to alter DumpMonger's behavior according to the needs of that particular code block. More on this later.
As to what we do with those four variables:
request.vars |
A comma-delimited list of all of the variable scopes we want to dump out in our diagnostics. It doesn't matter if they exist or not. We'll deal with that later. For now we should assemble a comprehensive list of every scope we want to see (this isn't all of them). I have opted to dump out the cfcatch and error scopes first, with the remaining ones coming out in alphabetical order* |
request.theFileName |
The name of the diagnostic file we will dump onto the disk. |
request.errorDirectory |
The complete path leading to the diagnostic file |
request.errorDomain |
The full url where the diagnostic file is located. Ideally this will be a secure connection and the folder will be protected with a permission block so the general public can't get to these files. |
*If you are using ColdFusion 5 some of these scopes are not exposed as structures. The routine will still work although you will not be able to see, for example, the client or variables scopes. |
Note that you could also assign these four variables in a given block of code like the first three. Our next step is to determine which version of ColdFusion we are running, which we will use a bit further on. You could hardwire this value in for more efficiency if you like.
The next thing DumpMonger does is pretty neat. It loops over the list of desired structures that we defined in request.vars. If any of them exist, they are added to the output variable we are building. Further, if we are running under ColdFusion 5 a label will be added to the output since CF5 doesn't display the same way CF6+ does. Structures which are not present in CF5 will simply be ignored.
The conversion of the output of our loop into a usable variable is made possible by wrapping it in the extremely handy CFSAVECONTENT tag, which neatly saves the result of the entire code block to variables.dataDump.
Our next step is a very simple cffile write operation, where the data we just collected is written to disk in a handy .html file (the extension could be .cfm depending on how you secure these output files... more on this later). Now that the data has been collected and stored, its time to do something with it. DumpMonger has three modes, which are executed immediately following the save:
- Standard mode dumps the error to disk, saves it and sends a copy of the saved file to the designated administrator via email.
- Secure mode dumps the error to disk and sends an email notice, but does not include a copy of the diagnostic data in the email. Instead it provides a (hopefully) secure link to the stored data.
- Onscreen mode simply dumps the data to the screen for your viewing pleasure.
Note that both Standard and Secure modes provide a direct link to the error template, as well as a link to a separate file: The Complete Error List. Before we get to that, lets talk about the security used to protect these stored files.
Protecting The Stored Diagnostic Files These error dumps are going to contain all sorts of useful information. The data will be especially useful to nefarious types who would like to get their mitts on your data and do unspeakable things with it. For example, if you collect credit card or other sensitive information on a form, and an error condition arose before you could encrypt the data... then some pretty valuable info will be sitting in the clear, happily dumped out with everything else (scenarios like this are a big reason why you shouldn't always mail error diagnostics to yourself).
The first thing you should do is only view these files over a secure connection. Since secure certificates are so cheap these days lets hope this is not a problem. Next, you have to protect anyone else from walking up and reading the files, secure connection or not.
The easiest thing to do is password-protect the directory containing these files. this is pretty easy to do, but it requires direct access to the server, which you may not have. If you don't have server access you have to switch to Plan B.
Listing 3 is a modified version of DumpMonger that adds in ColdFusion security. In this case we are adding code that will work with AccessMonger Lite/Pro (AMPro provides a direct pass-thru so you can link directly to a protected page, and then go to that page once you have logged in. AMLite is a 2-step process). AccessMonger Lite is a free download. The additional code is found in the new settings that create variables.Security. This data will be written in a new cffile statement that has been added to the routine. Note that this statement uses the AddNewLine parameter, as the original statement also now does. This ensures that between the two file writes nothing gets plugged onto the same line.
Viewing the Stored Diagnostic Files So we've dumped the data, saved it and protected it. Wouldn't it be nice to finally see it? If we are opting for secure mode, that part hasn't happened yet. Listing 4 provides this function. Before we get into the guts of it, lets take a look at the end result.
This file is really very simple to break down. We start out by setting the directory that contains all of the error diagnostic files. Next a quickee CFDirectory operation on this same location gives us our list to display. CFDirectory returns results in the form of a query, so we adjust the recordcount down by two to for reasons noted in the listing's code comments.
What comes next are the file actions that are executed in links further on down the template. This routine will perform two actions: Download a template to your hard disk (if you just want to look at it thats handled further on) and deletion.
The rest of this template is pretty straightforward html with a ColdFusion query loop thrown in. I'll leave it to you to puzzle through on your own
Installing The Site-Wide Handler in the CF Administrator Now that you have created the handler its time to install it. Open up the Administrator and visit the Settings screen.
At page bottom there are two entries. One for a custom 404 handler and another for a site-wide error handler. It is important to note that in versions of ColdFusion prior to CF6 (i.e. ColdFusion MX), this template was specified by a full physical path, as in
c:/inetpub/wwwroot/errors.cfm
Beginning with CF6, templates are specified as urls relative to the default web site on the server. So if your default website is at http://foo.com, and your error handler is located in the root folder, you would specify the location as
/errors.cfm
So, lets put in an entry. As long as we're here, we may as well also put in a custom 404 handler so we never have to worry about linkrot again. I'm partial to this template, which I call my404.cfm:
<cfset variables.GoPage="http://" & CGI.SERVER_NAME> <CFLOCATION URL="#variables.GoPage#" ADDTOKEN="No">
How tough was that? Now whenever someone hits a dead link they will be silently redirected to the domain's home page.
Got all that? Your turn.
-Matt Robertson- MSB Web Systems
|