SlideShare a Scribd company logo
1 of 52
Download to read offline
Don’t Ignore! 
Your Error Messages 
Mary Jo Sminkey! 
CF Webtools
About Me 
• 20+ Years in Web Development! 
• ColdFusion Developer since CF 3.0 Release by Allaire! 
• Author of the e-commerce application CFWebstore! 
• Currently working for CFWebtools as the Lead Developer for a large e-commerce 
website selling classic car parts (Classic Industries)! 
• Hobbies include dog training and showing, photography, playing music, 
baking, board games, scrapbooking, origami, and more!
There Will Always Be Bugs 
• "If debugging is the process of removing software bugs, then 
programming must be the process of putting them in." ! 
! – Edsger Dijkstra! 
! 
• “Programming today is a race between software engineers striving to 
build bigger and better idiot-proof programs, and the Universe trying to 
produce bigger and better idiots. So far, the Universe is winning.”! 
! – Rich Cook
Dealing with Bugs 
is Not FUN ! 
(But Necessary)
Developers Need To Be Brave
Classic Industries 
• Large Ecommerce Site for Classic Car Parts! 
• 3-4 million page views on average per month! 
• Approx. 400K unique visitors! 
• Averages 1-5 ColdFusion error reports per day
Why Are Bugs So Hard to Find? 
• "We have a bug that occurs on the 31st of a month so once a month 
we get a bug report. It gets assigned to a developer within 24 hours 
who then fiddles for a bit before marking it 'unable to reproduce'." ! 
• Multiple OS/browser environments to test ! 
• Increasing use of javascript, Ajax, other client-side code! 
• More complicated design patterns, use of frameworks, etc. versus 
procedural code: ! 
• “There are two ways of constructing a software design. One way is to 
make it so simple that there are obviously no deficiencies. And the 
other way is to make it so complicated that there are no obvious 
deficiencies."
Some Common Approaches to Error Handling 
• CFTry/Catch ! 
• Global Error Handler (onError or cferror)! 
! 
• Display User-Friendly Message to User! 
• Email Error Dump to Developer (maybe)
Common Problems with the Normal Approaches 
• Hiding errors that we may need to know about (try/catch blocks)! 
• Not enough information to figure out what happened to throw the error! 
• Receiving errors from hack attempts, causing us to waste time that 
should be spent tracking errors from legitimate users! 
• Lots of copies of the same error, wasting time to determine which are 
new errors and which are ones we’ve already reviewed! 
• Errors that we know about and expect to receive regularly
Global Error Handler - onError or CFError? 
• onError will not include ALL variable scopes! 
• cferror will include all scopes (other than local vars, but we can deal 
with that too)! 
• This does mean you will typically need to need to keep your 
Application.cfc tag based to some degree (pre-CF11). ! 
• Easiest is to put the cferror line in your OnRequestStart! 
• We will often wrap the cferror in a conditional test for which 
environments we want to show the CF errors versus using the error 
handler. ! 
• We also want to disable the error handler for MXUnit tests
Same CFError Include 
<cffunction name="OnRequestStart" returntype="boolean"> ! 
<cfif NOT ListFind( "local", application.environment) AND NOT ! 
! ! findNoCase("mxunit",cgi.script_name)>! 
! <cferror type="exception" template="errorhandler.cfm">! 
</cfif>! 
….! 
</cffunction>
Improving The Global Error Handler 
! 
• Remove any variable data internal to the error handler! 
• Filter out errors from search bots! 
• Allow use with try/catch blocks when we need to get data from the error ! 
• Skip common errors! 
• Include all relevant variables scopes! 
• Remove any secure data that is not safe to send via email! 
• Clean the variable scopes so we don’t get data we don’t need! 
• Process any data that might be encrypted or in some other format that 
what is most useful for the developer to get! 
• Don’t send lots of copies of the same error
ErrorHandler.cfm - Remove Vars used internally 
! 
• While this isn’t totally necessary, I don’t really care to see the 
variables I create within the error handler itself in my error emails. ! 
• So rather than using variables scope directly, I create a struct that is 
then used for all the local variables in the error handler, similar to how 
we used to typically do local variables in CFCs. ! 
! 
! <cfset localVars = structNew() />! ! 
! <cfset localVars.findBot = false />! 
! <cfset localVars.findExclude = false />
ErrorHandler.cfm - Skip Errors from Bots 
! 
• You may prefer to receive these errors depending on your level of 
error handling for malformed URLs and invalid params. ! 
• There are other more sophisticated ways to detect browser types 
such as 3rd party plugins like Browser Hawk, but this is a simple way 
to exclude most of the common ones. ! 
! 
!
ErrorHandler.cfm - Skip Errors from Bots 
! 
<cfset localVars.botList = "bot,spider,crawl,jeeves,yahoo,slurp" />! 
! 
<cfloop index="localVars.item" list="#localVars.botList#">! 
! <cfif FindNoCase(localVars.item, CGI.HTTP_USER_AGENT)>! 
! ! <cfset localVars.findBot = true />! 
! </cfif>! 
</cfloop>! 
! 
<cfif NOT localVars.findBot>! 
! Continue with error handler… ! 
</cfif>
ErrorHandler.cfm - Use for both cferror and cfcatch 
! 
• By coding the error handler to be available for use in a try/catch block we can drop 
it into places in the code where we are having trouble debugging what is 
happening, to get more information on the error. ! 
• This is particularly useful in CFC methods, where the global error handler won’t 
have any data about the local vars. ! 
• The error structure we receive for global errors versus inside a cfcatch is different. ! 
• We need to detect these and set up variables for the areas in the code where we 
are going to be outputting the error data. ! 
• When used in a cfcatch block, we may want to skip parts of the error handler, such 
as displaying a user-friendly error message. ! 
!
ErrorHandler.cfm - Use for both cferror and cfcatch 
! 
<cfif isDefined("error.Diagnostics")>! 
! <cfset localVars.errormess = error.Diagnostics>! 
! <cfset localVars.errorData = error>! 
! <cfparam name="request.errorType" default="fatal" >! 
<cfelseif isDefined("cfcatch.message")>! 
! <cfset localVars.errormess = cfcatch.message>! 
! <cfset localVars.errorData = cfcatch>! 
! <cfparam name="request.errorType" default="error" >! 
</cfif>! 
!
ErrorHandler.cfm - Skip Common Errors 
! 
• For some sites, you may have errors that you wish to detect due to them 
occurring frequently and not being fixable. ! 
• How you handle them may vary based on your environment and other 
detection methods for your sites (up-time detection, etc.) ! 
• For instance, for one client we frequently have database issues where lots of 
timeout errors get thrown regularly. This is a known issue the client has 
decided not to address at the time so while we log the number of times and 
pages they occur on, we don’t need to receive emails for them. ! 
• We also ran into a bug where a malformed returnFormat in an Ajax call to a 
CFC throws an error that can not be handled via other methods. ! 
!
ErrorHandler.cfm - Skip Common Errors 
! 
! 
! 
<cfset localVars.errorExcludeList = "Execution timeout expired,request has 
exceeded the allowable time limit,Invalid returnFormat: jsPr”/>! 
! 
<cfloop index="localVars.item" list="#localVars.errorExcludeList#">! 
! <cfif isDefined("error") AND FindNoCase(localVars.item, error.diagnostics)>! 
! ! <cfset localVars.findExclude = true />! 
! <cfelseif isDefined("cfcatch") AND FindNoCase(localVars.item, 
cfcatch.message)>! 
! ! <cfset localVars.findExclude = true />! 
! </cfif>! 
</cfloop>
ErrorHandler.cfm - What to Include 
! 
• What scopes you include will depend on your site and what types of 
activities ColdFusion is doing. ! 
• We will also need to set up a list of “secure” variables that we are 
going to want to exclude! 
• If you want to scrub the data for sensitive data, typically you will want 
to also create a list of scopes to scrub.! 
!
ErrorHandler.cfm - What to Include 
! 
localVars.varstodump=“CFCATCH,ERROR,APPLICATION,ARGUMENTS, 
ATTRIBUTES,CALLER,CGI,CLIENT,CFHTTP,FILE,FORM,REQUEST, 
SESSION, COOKIE,THIS,THISTAG,URL,VARIABLES";! 
! 
localVars.varstoscrub=“ATTRIBUTES,ARGUMENTS,CGI,FORM,REQUEST, 
SESSION,URL,VARIABLES,COOKIE,CFCATCH,ERROR";! 
! 
localVars.securevars=“CFID,CFTOKEN,JSESSIONID,SessionID,URLToken, 
password,newpassword,customerID,ccName,ccNumber,cvv2,encryptkey";! 
!
ErrorHandler.cfm - Creating the Error Dumps 
! 
• Now that we have our list of variables we want to output in our error logs and/or 
emails, we’ll loop over the list and dump each scope. ! 
• We will do some special handling for some scopes. This will include those that we list 
as potentially having secure information and scopes like Application that may have 
data like a bean factory that we don’t want to output in error messages. ! 
• Your application may have specific error scopes that have their own special handling. 
For instance, we set encrypted cookies for things like the customer ID on the site. 
For the error handler, I decrypt that string so that I have the actual customer ID to 
look up info in the database. Another example might be if I want to use the shopping 
cart ID to include a dump of the actual shopping cart contents in the emails. ! 
!
ErrorHandler.cfm - Creating the Error Dumps 
<cfsavecontent variable="localVars.dataDump">! 
! ! 
! <cfloop list="#localVars.varstodump#" index=“localVars.loopItem">! 
! ! ! 
! ! Code to parse and dump out the variable scopes here!! 
! 
! </cfloop>! 
! 
</cfsavecontent>! 
! 
!
ErrorHandler.cfm - Checking for CFC methods 
! 
• One thing I always want to exclude from error dumps are user-defined functions and 
components.! 
• If you use a bean factory like Coldspring or Wirebox, it’s usually just an easy matter of 
excluding it in the appropriate scope dump. ! 
• If however, you have a collection of components and/or functions in something like 
Application scope you may need to manually exclude it.! 
• For components, you can use IsCFC() on CFLib.org written by Nathan Dintenfass.! 
• For user-defined (or built-in) functions, use IsFunction() also on CFLib.org, written by 
Ray Camden. ! 
• You can also use the showUDFs attribute on the cfdump tag itself. ! 
!
ErrorHandler.cfm - Sample Dump for Application Scope 
! 
<cfif IsDefined("#localVars.loopItem#") AND localVars.loopItem IS “APPLICATION">! 
<cfset localVars.ApplicationVars = StructNew()>! 
<cfset localVars.listExclude = "blogCache,errorLog" />! 
<cfloop item="localVars.each" collection=“#Application#">! 
<cfif NOT IsCFC( Application[localVars.each] ) AND NOT ! 
! ! ListFindNoCase(localVars.listExclude, localVars.each)>! 
<cfset localVars.ApplicationVars[localVars.each] = Application[localVars.each]>! 
</cfif>! 
</cfloop>! 
! 
<cfset request.cfdumpinited=“false”>! 
<cfdump var="#localVars.ApplicationVars#" label=“Application" showUDFs=“false”>
ErrorHandler.cfm - Sample Dump to Scrub Scopes 
<cfelseif IsDefined("#localVars.loopItem#") AND ListFind(localVars.varstoscrub,localVars.loopItem)>! 
<cfset localVars.ScrubbedVars = structNew()>! 
<cfset localVars.scopeToCheck = Evaluate(localVars.loopItem) />! 
<cfloop item="localVars.each" collection="#localVars.scopeToCheck#">! 
<cfif ListFindNoCase(localVars.securevars,localVars.each)>! 
<cfset localVars.ScrubbedVars[localVars.each] = "removed">! ! ! ! ! 
<cfelse>! 
<cfset localVars.listremove = "GeneratedContent,CFCatch,CFError,Error,localVars,IsCFC">! 
<cfif NOT ListFindNoCase(localVars.listremove,localVars.each) ! 
! AND NOT IsCFC(localVars.scopeToCheck[localVars.each]) ! 
! AND NOT structKeyExists(localVars.ScrubbedVars, localVars.each)>! 
<cfset localVars.ScrubbedVars[localVars.each]= localVars.scopeToCheck[localVars.each]>! 
</cfif>! 
</cfif>! 
</cfloop>! 
<cfset request.cfdumpinited=“false”>! 
<cfdump var="#localVars.ScrubbedVars#" label="Scrubbed #localVars.loopitem#” showUDFs=“false”>
ErrorHandler.cfm - Dump Remaining Scopes 
<cfsavecontent>! 
<cfloop … >! 
<cfif … >! 
Scrubbed var scopes! 
<cfelseif IsDefined("#localVars.loopItem#")>! 
<cfset request.cfdumpinited=“false”> ! 
<cfdump var="#localVars.ScrubbedVars#" label=“#localVars.loopitem#” showUDFs=“false”>! 
</cfif>! 
</cfloop>! 
</cfsavecontent>!
ErrorHandler.cfm - Error Summary 
<cfsavecontent variable="localVars.basicinfo">! 
<cfoutput>! 
<table width="100%" cellpadding="5" cellspacing="0" border="0">! 
<cfloop collection="#localVars.errorData#" item="localVars.i">! 
<cfset localVars.data = localVars.errorData[localVars.i]>! 
<cfif IsSimpleValue(localVars.data) AND localVars.i IS NOT "GeneratedContent">! 
<tr><td>! 
<strong>#Ucase(localVars.i)#:</strong><br/>#localVars.data#! 
</td></tr>! 
</cfif>! 
</cfloop>! 
</table>! 
</cfoutput>! 
</cfsavecontent>
ErrorHandler.cfm - Swap Settings for Error Type 
<cfswitch expression="#request.errorType#">! 
<cfcase value="init">! 
<cfset subject = "Error starting up #cgi.server_name#">! 
<cfset errorMessage = "#cgi.server_name# was not able to start up.”>! 
<cfset toAddr =“webmaster@cfwebtools.com" />! 
</cfcase>! 
<cfdefaultcase>! 
<cfset subject = "Error on #cgi.server_name#">! 
<cfset errorMessage = "An error has been encountered on #cgi.server_name#:”>! 
<cfset toAddr = "errors@cfwebtools.com">! 
</cfdefaultcase>! 
</cfswitch>!
ErrorHandler.cfm - Eliminating Duplicate Errors 
• We don’t need to get many copies of the same error via email! 
• This makes it a lot harder to not only get an idea of how many different errors we have to 
review, but takes time opening and loading each email to see if it is unique. ! 
• There’s different ways you can handle this but the easiest is to just log each error in the 
application scope and then check it before adding new errors. ! 
• Typically I log each error only once every 4 hours, but you can use longer time frames 
based on tracking multiple errors as follows. ! 
• By keeping a count of the errors we can check if multiple copies of the error are being 
thrown. This can alert us to a critical situation on the server that may need to be 
addressed immediately. ! 
• I also typically use this with some of the errors that are common and I don’t need to get 
emails for single instances. ! 
• So we also want to track the number of times each error has been thrown in order to 
generate an email every X number of times (I use 25).
ErrorHandler.cfm - Eliminating Duplicate Errors 
<cfif NOT StructKeyExists(Application.ErrorLog, localVars.Errormess) ! 
! OR DateCompare( Application.ErrorLog[ localVars.Errormess ].TimeError, ! 
! DateAdd("h", -4, Now() ) ) LT 0 >! 
! Generate Error Dumps Email here….! 
<cfif request.errorType IS NOT "init">! ! ! ! ! 
<cfset Application.ErrorLog[localVars.Errormess] = TimeError: Now(), Count: 1 } />! 
</cfif>! 
<cfelse>! 
<cfset Application.ErrorLog[localVars.Errormess].Count++ />! 
<cfif Application.ErrorLog[localVars.Errormess].Count MOD 25 EQ 0>! 
Generate Multiple Errors Email here….! 
</cfif>! 
</cfif>
ErrorHandler.cfm - Sample Email 
<cfif NOT localVars.findExclude>! 
<cfmail to="#toAddr#" from=“no-reply@cfwebtools.com“! 
subject="#subject#" type="HTML">! 
<br/><br/>! 
#errorMessage#<br/><br/>! 
#localVars.basicinfo#<br/><br/>! 
<strong>Full message:</strong><br/><br/>! 
#localVars.dataDump#<br/><br/>! 
</cfmail>! 
</cfif>
ErrorHandler.cfm - Sample Multiple Errors Email 
<cfmail to="#toAddr#" from=“no-reply@cfwebtools.com“! 
subject=“MULTIPLE ERRORS ON #subject#" type="HTML">! 
<br/><br/>! 
The following error has occurred 
#Application.ErrorLog[localVars.errormess].Count# times in the last four hours 
on #cgi.server_name#:! 
#errorMessage#<br/><br/>! 
#localVars.basicinfo#<br/><br/>! 
<strong>Full message:</strong><br/><br/>! 
#localVars.dataDump#<br/><br/>! 
</cfmail>
ErrorHandler.cfm - Show User Friendly Error Page 
• Based on the error type, we may or may not need to display a 
message to the user (for instance, error in a try/catch block we most 
likely will not)! 
• We will first try to display a page using the full site template. ! 
• If that page itself errors out though, we should have a very simple 
HTML only error page available as a fallback. ! 
• We also include analytics on the page itself to keep counts of 
different types of errors encountered.
ErrorHandler.cfm - Show User Friendly Error Page 
<cfif NOT ListFind("email,cfcatch", request.errorType)>! 
<cftry>! ! 
<cfset action = "cferror">! ! 
<cfinclude template="/controller/linkcontroller.cfm" />! 
<cfabort>! 
! 
<cfcatch type="any" >! 
<cfinclude template="displayerror.cfm">! 
<cfabort>! 
</cfcatch>! 
</cftry>! 
</cfif>
ErrorHandler.cfm - Using in Try/Catch Blocks 
• The error handler will be used automatically for any unhanded CF 
errors. ! 
• However, one issue is that errors that occur inside CFCs will not include 
the local scoped variables. ! 
• Therefore, you may want to use the error handler inside a try/catch 
block particularly if you are trying to debug a specific error and need a 
copy of the local variables. ! 
• In order to see what the local vars are set to at the time of the error, you 
will need to copy them to another scope prior to calling the error handler. ! 
• We also use the error handler to notify us if there is some issue with 
application initialization.
ErrorHandler.cfm - Using in Try/Catch Blocks 
function name…. {! 
try {! 
code here that we need to debug….! 
} catch (any err) {! 
! //copy our local scope to request! 
! request.functionLocal = Duplicate(local);! 
! include “/views/errors/errorhandler.cfm”;! 
}! 
}!
Tracking User Actions - Page Tracker 
• One thing that the error handler does not tell us is what the user might have 
done to cause the error. ! 
• We only know what happened at best for that request, but there are times when 
we may want to know the other actions the user performed prior to the error. ! 
• This can be particularly useful for errors thrown by Ajax requests, where we at 
least want to know the page there user was on and what they did to generate 
the Ajax call.! 
• Since our application already makes use of sessions, it makes sense to log the 
page requests into the session so that they automatically show up in the error 
handler. ! 
• We also include this session object into support emails since users 
typically do not include detailed information about what they were doing 
when they ran into a problem.
Tracking User Actions - Page Tracker 
function onSessionStart() {! 
! //initialize the page tracker! 
! session.pageTracker = arrayNew(1);! 
}
Tracking User Actions - Page Tracker 
function onRequestStart() {! 
request.thisPage = cgi.script_name & '?' & cgi.query_string;! 
if ( !arrayLen(session.pageTracker) IS 0 OR ! 
! ! session.pageTracker[1] IS NOT request.thisPage ) {! ! 
lock scope="session" type="exclusive" timeout="10" {!! ! ! ! 
if ( arrayLen(session.pageTracker) LT 20 ) {! 
arrayPrepend(session.pageTracker,request.thisPage);! 
} else {! 
arrayDeleteAt(session.pageTracker,arrayLen(session.pageTracker));! 
arrayPrepend(session.pageTracker,request.thisPage);! 
}! 
}! 
}! 
}
Tracking User Actions - User Info 
• If you use sessions, you might find it useful to load data into the session that 
can help you debug.! 
• For instance, we typically put the user email, customer ID, and name into the 
session when user logs in, even though this information is not otherwise used 
from the session scope. ! 
• This not only helps in cases where we need to review related customer data 
that might have caused the problem but that way we can also contact the 
customer once we have corrected the customer. Nothing impresses your 
users more than actually getting an email from your site telling them the 
problem they ran into when they were trying to shop has been fixed! ! 
• We also include this session information into support emails that get sent 
from the site, again since users have a tendency to do things like mistype 
their email if we ask them to enter it.
BugLogHQ 
• BugLogHQ is a free, open source CFML tool to centralize the handling of 
bug reports for multiple applications. ! 
• It allows you to view, search, graph, report, and subscribe to bugs from 
your applications. ! 
• However, BugLogHQ does not include all the variable scopes that my 
global error can send out. ! 
• It does not typically include any scrubbing of the error data for possible 
secure items.! 
• Also, if you are sending every single error to it, you can overwhelm the 
database with error entries, particularly if you are working with an 
application that generates large numbers of errors, or cause an repetitive 
bug in development.
BugLogHQ - Features 
• BugLogHQ has a powerful Rules feature to set up email notifications of 
errors, which include different rule types such as only the FirstInstance of 
an error, specific error messages, or daily summaries of errors. ! 
• We find this particularly useful for clients where we often use different 
developers on tasks, so that they can turn error reporting on and off as 
needed. ! 
• You can also set BugLogHQ to purge its errors on a regular basis. ! 
• BugLogHQ can also run “heartbeat” monitors to check that your website is 
running properly.
BugLogHQ - Installation 
• Software and documentation found at http://www.bugloghq.com. ! 
• Runs on CF 8+ or Railo and mySQL or SQL Server. ! 
• Errors can be sent to BugLog using web service, HTTP post, or CFC call. ! 
• Includes clients for ColdFusion, Python, PHP and Javascript! 
! 
Application.cfc - onApplicationStart() :! 
application.bugLogService = ! 
! createObject(“component", “buglog.client.bugLogService”).init(! 
! bugLogListener = ‘http://buglog:8080/listeners/bugLogListenerREST.cfm’);! 
! ! ! ! !
BugLogHQ - Usage in Error Handler 
• To send all our variable scopes to BugLog, we need to have a single object 
to include in the web service call. ! 
• Since BugLog already includes the error or cfcatch data, we don’t need to 
include those.! 
• We can also include an error type, which can be used as a filter in the 
BugLogHQ reports.! 
• I like to log even the errors that I typically don’t email on the first instance, 
so that I still have some idea how often those are occurring.
BugLogHQ - Copying Variable Scopes 
localVars.strScopes = structNew();! 
….! 
<cfdump var="#localVars.ScrubbedVars#" label="Scrubbed #localVars.loopitem#">! 
<cfif NOT ListFind(“ERROR, CFCATCH”, localVars.loopitem)>! 
<cfset localVars.strScopes[localVars.loopitem] = localVars.ScrubbedVars />! 
<cfelse>! 
<cfset localVars.errorData = localVars.ScrubbedVars>! 
</cfif>! 
…! 
<cfdump var="#Evaluate(localVars.loopItem)#" label="#localVars.loopItem#">! 
<cfset localVars.strScopes[localVars.loopitem] = Evaluate(localVars.loopItem) />!
BugLogHQ - Logging the Error 
<cfif NOT localVars.findExclude>! 
! … mail the error as usual! 
</cfif>! 
<!—- we check to make sure the bug log service is available (local dev) —->! 
<cfif structKeyExists(application,"bugLogService")>! 
<cfset application.bugLogService.notifyService(! 
! ! ! localVars.errormess, ! 
! ! ! localVars.errorData, ! 
! ! ! localVars.strScopes, ! 
! ! ! request.errorType)>! 
</cfif>
Debugging Javascript Errors 
• Today’s applications typically have considerable javascript running on 
them! 
• jQuery, Bootstrap, AngularJS, and other libraries make sites more 
feature rich and user friendly, but harder to debug remote client issues. ! 
• How then can we figure out what the cause of a user’s issue is when we 
can’t see the Javascript error thrown by their browser? ! 
• BugLogHS does include a JS client but you will need to include it into 
your JS code. ! 
• There are a variety of excellent 3rd party services you can use for 
logging and tracking JS bugs.
Javascript Error Reporting Tools 
• trackjs.com! 
• qbaka.com! 
• errorception.com! 
• jslogger.com! 
• muscula.com! 
• exceptionhub.com! 
• jserrlog.appspot.com (OSS)! 
• github.com/occ/TraceKit
Mobile Error Monitoring Tools 
These can be used to monitor and track mobile device errors. ! 
• bugsense.com! 
• bugsnag.com
BrowserHawk 
• BrowserHawk is an Enterprise-level tool for testing client environments 
for requirements for your websites or website features.! 
• It includes both a web service, and a JAR you can install on the server, 
to use in ColdFusion pages to test and/or log information about the client 
environment. ! 
• They also have a Javascript logging tool which works via webservice. ! 
• We have used BrowserHawk not just for testing compatibility for our site, 
but to check for search bots prior to generating errors, as well as 
including data about the client in support emails.
Questions?

More Related Content

What's hot

Even Faster Web Sites at The Ajax Experience
Even Faster Web Sites at The Ajax ExperienceEven Faster Web Sites at The Ajax Experience
Even Faster Web Sites at The Ajax ExperienceSteve Souders
 
Enter the app era with ruby on rails (rubyday)
Enter the app era with ruby on rails (rubyday)Enter the app era with ruby on rails (rubyday)
Enter the app era with ruby on rails (rubyday)Matteo Collina
 
jQuery from the very beginning
jQuery from the very beginningjQuery from the very beginning
jQuery from the very beginningAnis Ahmad
 
Making Web Development "Secure By Default"
Making Web Development "Secure By Default" Making Web Development "Secure By Default"
Making Web Development "Secure By Default" Duo Security
 
Opening up the Social Web - Standards that are bridging the Islands
Opening up the Social Web - Standards that are bridging the IslandsOpening up the Social Web - Standards that are bridging the Islands
Opening up the Social Web - Standards that are bridging the IslandsBastian Hofmann
 
Bullet: The Functional PHP Micro-Framework
Bullet: The Functional PHP Micro-FrameworkBullet: The Functional PHP Micro-Framework
Bullet: The Functional PHP Micro-FrameworkVance Lucas
 
Jacob Waller: Webifying Titanium Development
Jacob Waller: Webifying Titanium DevelopmentJacob Waller: Webifying Titanium Development
Jacob Waller: Webifying Titanium DevelopmentAxway Appcelerator
 
(BDT402) Performance Profiling in Production: Analyzing Web Requests at Scale...
(BDT402) Performance Profiling in Production: Analyzing Web Requests at Scale...(BDT402) Performance Profiling in Production: Analyzing Web Requests at Scale...
(BDT402) Performance Profiling in Production: Analyzing Web Requests at Scale...Amazon Web Services
 
jQuery Anti-Patterns for Performance & Compression
jQuery Anti-Patterns for Performance & CompressionjQuery Anti-Patterns for Performance & Compression
jQuery Anti-Patterns for Performance & CompressionPaul Irish
 
Beyond MVC: from Model to Domain
Beyond MVC: from Model to DomainBeyond MVC: from Model to Domain
Beyond MVC: from Model to DomainJeremy Cook
 
VSA: The Virtual Scripted Attacker, Brucon 2012
VSA: The Virtual Scripted Attacker, Brucon 2012VSA: The Virtual Scripted Attacker, Brucon 2012
VSA: The Virtual Scripted Attacker, Brucon 2012Abraham Aranguren
 
Getting Started with DOM
Getting Started with DOMGetting Started with DOM
Getting Started with DOMHernan Mammana
 

What's hot (13)

Ruby on Rails
Ruby on RailsRuby on Rails
Ruby on Rails
 
Even Faster Web Sites at The Ajax Experience
Even Faster Web Sites at The Ajax ExperienceEven Faster Web Sites at The Ajax Experience
Even Faster Web Sites at The Ajax Experience
 
Enter the app era with ruby on rails (rubyday)
Enter the app era with ruby on rails (rubyday)Enter the app era with ruby on rails (rubyday)
Enter the app era with ruby on rails (rubyday)
 
jQuery from the very beginning
jQuery from the very beginningjQuery from the very beginning
jQuery from the very beginning
 
Making Web Development "Secure By Default"
Making Web Development "Secure By Default" Making Web Development "Secure By Default"
Making Web Development "Secure By Default"
 
Opening up the Social Web - Standards that are bridging the Islands
Opening up the Social Web - Standards that are bridging the IslandsOpening up the Social Web - Standards that are bridging the Islands
Opening up the Social Web - Standards that are bridging the Islands
 
Bullet: The Functional PHP Micro-Framework
Bullet: The Functional PHP Micro-FrameworkBullet: The Functional PHP Micro-Framework
Bullet: The Functional PHP Micro-Framework
 
Jacob Waller: Webifying Titanium Development
Jacob Waller: Webifying Titanium DevelopmentJacob Waller: Webifying Titanium Development
Jacob Waller: Webifying Titanium Development
 
(BDT402) Performance Profiling in Production: Analyzing Web Requests at Scale...
(BDT402) Performance Profiling in Production: Analyzing Web Requests at Scale...(BDT402) Performance Profiling in Production: Analyzing Web Requests at Scale...
(BDT402) Performance Profiling in Production: Analyzing Web Requests at Scale...
 
jQuery Anti-Patterns for Performance & Compression
jQuery Anti-Patterns for Performance & CompressionjQuery Anti-Patterns for Performance & Compression
jQuery Anti-Patterns for Performance & Compression
 
Beyond MVC: from Model to Domain
Beyond MVC: from Model to DomainBeyond MVC: from Model to Domain
Beyond MVC: from Model to Domain
 
VSA: The Virtual Scripted Attacker, Brucon 2012
VSA: The Virtual Scripted Attacker, Brucon 2012VSA: The Virtual Scripted Attacker, Brucon 2012
VSA: The Virtual Scripted Attacker, Brucon 2012
 
Getting Started with DOM
Getting Started with DOMGetting Started with DOM
Getting Started with DOM
 

Viewers also liked

Cardiovascular Disease
Cardiovascular DiseaseCardiovascular Disease
Cardiovascular Diseasebecause789
 
Forum Romanium
Forum RomaniumForum Romanium
Forum Romaniumbecause789
 
Facts of Early US History
Facts of Early US HistoryFacts of Early US History
Facts of Early US Historybecause789
 
SB 1070 vs. Genocide
SB 1070 vs. GenocideSB 1070 vs. Genocide
SB 1070 vs. Genocidebecause789
 

Viewers also liked (6)

Cardiovascular Disease
Cardiovascular DiseaseCardiovascular Disease
Cardiovascular Disease
 
D&r capital bird dog
D&r capital bird dogD&r capital bird dog
D&r capital bird dog
 
Forum Romanium
Forum RomaniumForum Romanium
Forum Romanium
 
The Olympians
The OlympiansThe Olympians
The Olympians
 
Facts of Early US History
Facts of Early US HistoryFacts of Early US History
Facts of Early US History
 
SB 1070 vs. Genocide
SB 1070 vs. GenocideSB 1070 vs. Genocide
SB 1070 vs. Genocide
 

Similar to Don't Ignore Your Errors!

"Running CF in a Shared Hosting Environment"
"Running CF in a Shared Hosting Environment""Running CF in a Shared Hosting Environment"
"Running CF in a Shared Hosting Environment"webhostingguy
 
Advanced Error Handling Strategies for ColdFusion
Advanced Error Handling Strategies for ColdFusion Advanced Error Handling Strategies for ColdFusion
Advanced Error Handling Strategies for ColdFusion Mary Jo Sminkey
 
Web Hacking Series Part 4
Web Hacking Series Part 4Web Hacking Series Part 4
Web Hacking Series Part 4Aditya Kamat
 
Moved to https://slidr.io/azzazzel/web-application-performance-tuning-beyond-xmx
Moved to https://slidr.io/azzazzel/web-application-performance-tuning-beyond-xmxMoved to https://slidr.io/azzazzel/web-application-performance-tuning-beyond-xmx
Moved to https://slidr.io/azzazzel/web-application-performance-tuning-beyond-xmxMilen Dyankov
 
Sql Injections With Real Life Scenarious
Sql Injections With Real Life ScenariousSql Injections With Real Life Scenarious
Sql Injections With Real Life ScenariousFrancis Alexander
 
Mitigating CSRF with two lines of codes
Mitigating CSRF with two lines of codesMitigating CSRF with two lines of codes
Mitigating CSRF with two lines of codesMinhaz A V
 
Browser Security 101
Browser Security 101 Browser Security 101
Browser Security 101 Stormpath
 
2010 za con_daniel_cuthbert
2010 za con_daniel_cuthbert2010 za con_daniel_cuthbert
2010 za con_daniel_cuthbertJohan Klerk
 
Stapling and patching the web of now - ForwardJS3, San Francisco
Stapling and patching the web of now - ForwardJS3, San FranciscoStapling and patching the web of now - ForwardJS3, San Francisco
Stapling and patching the web of now - ForwardJS3, San FranciscoChristian Heilmann
 
4. Web programming MVC.pptx
4. Web programming  MVC.pptx4. Web programming  MVC.pptx
4. Web programming MVC.pptxKrisnaBayu41
 
Influx/Days 2017 San Francisco | Emily Nakashima
Influx/Days 2017 San Francisco | Emily NakashimaInflux/Days 2017 San Francisco | Emily Nakashima
Influx/Days 2017 San Francisco | Emily NakashimaInfluxData
 
Northeast PHP - High Performance PHP
Northeast PHP - High Performance PHPNortheast PHP - High Performance PHP
Northeast PHP - High Performance PHPJonathan Klein
 
Velocity building a performance lab for mobile apps in a day - final
Velocity   building a performance lab for mobile apps in a day - finalVelocity   building a performance lab for mobile apps in a day - final
Velocity building a performance lab for mobile apps in a day - finalAshray Mathur
 
Rails antipattern-public
Rails antipattern-publicRails antipattern-public
Rails antipattern-publicChul Ju Hong
 

Similar to Don't Ignore Your Errors! (20)

"Running CF in a Shared Hosting Environment"
"Running CF in a Shared Hosting Environment""Running CF in a Shared Hosting Environment"
"Running CF in a Shared Hosting Environment"
 
Advanced Error Handling Strategies for ColdFusion
Advanced Error Handling Strategies for ColdFusion Advanced Error Handling Strategies for ColdFusion
Advanced Error Handling Strategies for ColdFusion
 
Web Hacking Series Part 4
Web Hacking Series Part 4Web Hacking Series Part 4
Web Hacking Series Part 4
 
Moved to https://slidr.io/azzazzel/web-application-performance-tuning-beyond-xmx
Moved to https://slidr.io/azzazzel/web-application-performance-tuning-beyond-xmxMoved to https://slidr.io/azzazzel/web-application-performance-tuning-beyond-xmx
Moved to https://slidr.io/azzazzel/web-application-performance-tuning-beyond-xmx
 
Sql Injections With Real Life Scenarious
Sql Injections With Real Life ScenariousSql Injections With Real Life Scenarious
Sql Injections With Real Life Scenarious
 
Mitigating CSRF with two lines of codes
Mitigating CSRF with two lines of codesMitigating CSRF with two lines of codes
Mitigating CSRF with two lines of codes
 
Beyond Phoenix
Beyond PhoenixBeyond Phoenix
Beyond Phoenix
 
WebSockets with Spring 4
WebSockets with Spring 4WebSockets with Spring 4
WebSockets with Spring 4
 
Browser Security 101
Browser Security 101 Browser Security 101
Browser Security 101
 
Php
PhpPhp
Php
 
orcreatehappyusers
orcreatehappyusersorcreatehappyusers
orcreatehappyusers
 
orcreatehappyusers
orcreatehappyusersorcreatehappyusers
orcreatehappyusers
 
Refactoring
RefactoringRefactoring
Refactoring
 
2010 za con_daniel_cuthbert
2010 za con_daniel_cuthbert2010 za con_daniel_cuthbert
2010 za con_daniel_cuthbert
 
Stapling and patching the web of now - ForwardJS3, San Francisco
Stapling and patching the web of now - ForwardJS3, San FranciscoStapling and patching the web of now - ForwardJS3, San Francisco
Stapling and patching the web of now - ForwardJS3, San Francisco
 
4. Web programming MVC.pptx
4. Web programming  MVC.pptx4. Web programming  MVC.pptx
4. Web programming MVC.pptx
 
Influx/Days 2017 San Francisco | Emily Nakashima
Influx/Days 2017 San Francisco | Emily NakashimaInflux/Days 2017 San Francisco | Emily Nakashima
Influx/Days 2017 San Francisco | Emily Nakashima
 
Northeast PHP - High Performance PHP
Northeast PHP - High Performance PHPNortheast PHP - High Performance PHP
Northeast PHP - High Performance PHP
 
Velocity building a performance lab for mobile apps in a day - final
Velocity   building a performance lab for mobile apps in a day - finalVelocity   building a performance lab for mobile apps in a day - final
Velocity building a performance lab for mobile apps in a day - final
 
Rails antipattern-public
Rails antipattern-publicRails antipattern-public
Rails antipattern-public
 

Recently uploaded

Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machinePadma Pradeep
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxNavinnSomaal
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsMiki Katsuragi
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxhariprasad279825
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 

Recently uploaded (20)

Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machine
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptx
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering Tips
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptx
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 

Don't Ignore Your Errors!

  • 1. Don’t Ignore! Your Error Messages Mary Jo Sminkey! CF Webtools
  • 2. About Me • 20+ Years in Web Development! • ColdFusion Developer since CF 3.0 Release by Allaire! • Author of the e-commerce application CFWebstore! • Currently working for CFWebtools as the Lead Developer for a large e-commerce website selling classic car parts (Classic Industries)! • Hobbies include dog training and showing, photography, playing music, baking, board games, scrapbooking, origami, and more!
  • 3. There Will Always Be Bugs • "If debugging is the process of removing software bugs, then programming must be the process of putting them in." ! ! – Edsger Dijkstra! ! • “Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning.”! ! – Rich Cook
  • 4. Dealing with Bugs is Not FUN ! (But Necessary)
  • 6. Classic Industries • Large Ecommerce Site for Classic Car Parts! • 3-4 million page views on average per month! • Approx. 400K unique visitors! • Averages 1-5 ColdFusion error reports per day
  • 7. Why Are Bugs So Hard to Find? • "We have a bug that occurs on the 31st of a month so once a month we get a bug report. It gets assigned to a developer within 24 hours who then fiddles for a bit before marking it 'unable to reproduce'." ! • Multiple OS/browser environments to test ! • Increasing use of javascript, Ajax, other client-side code! • More complicated design patterns, use of frameworks, etc. versus procedural code: ! • “There are two ways of constructing a software design. One way is to make it so simple that there are obviously no deficiencies. And the other way is to make it so complicated that there are no obvious deficiencies."
  • 8. Some Common Approaches to Error Handling • CFTry/Catch ! • Global Error Handler (onError or cferror)! ! • Display User-Friendly Message to User! • Email Error Dump to Developer (maybe)
  • 9. Common Problems with the Normal Approaches • Hiding errors that we may need to know about (try/catch blocks)! • Not enough information to figure out what happened to throw the error! • Receiving errors from hack attempts, causing us to waste time that should be spent tracking errors from legitimate users! • Lots of copies of the same error, wasting time to determine which are new errors and which are ones we’ve already reviewed! • Errors that we know about and expect to receive regularly
  • 10. Global Error Handler - onError or CFError? • onError will not include ALL variable scopes! • cferror will include all scopes (other than local vars, but we can deal with that too)! • This does mean you will typically need to need to keep your Application.cfc tag based to some degree (pre-CF11). ! • Easiest is to put the cferror line in your OnRequestStart! • We will often wrap the cferror in a conditional test for which environments we want to show the CF errors versus using the error handler. ! • We also want to disable the error handler for MXUnit tests
  • 11. Same CFError Include <cffunction name="OnRequestStart" returntype="boolean"> ! <cfif NOT ListFind( "local", application.environment) AND NOT ! ! ! findNoCase("mxunit",cgi.script_name)>! ! <cferror type="exception" template="errorhandler.cfm">! </cfif>! ….! </cffunction>
  • 12. Improving The Global Error Handler ! • Remove any variable data internal to the error handler! • Filter out errors from search bots! • Allow use with try/catch blocks when we need to get data from the error ! • Skip common errors! • Include all relevant variables scopes! • Remove any secure data that is not safe to send via email! • Clean the variable scopes so we don’t get data we don’t need! • Process any data that might be encrypted or in some other format that what is most useful for the developer to get! • Don’t send lots of copies of the same error
  • 13. ErrorHandler.cfm - Remove Vars used internally ! • While this isn’t totally necessary, I don’t really care to see the variables I create within the error handler itself in my error emails. ! • So rather than using variables scope directly, I create a struct that is then used for all the local variables in the error handler, similar to how we used to typically do local variables in CFCs. ! ! ! <cfset localVars = structNew() />! ! ! <cfset localVars.findBot = false />! ! <cfset localVars.findExclude = false />
  • 14. ErrorHandler.cfm - Skip Errors from Bots ! • You may prefer to receive these errors depending on your level of error handling for malformed URLs and invalid params. ! • There are other more sophisticated ways to detect browser types such as 3rd party plugins like Browser Hawk, but this is a simple way to exclude most of the common ones. ! ! !
  • 15. ErrorHandler.cfm - Skip Errors from Bots ! <cfset localVars.botList = "bot,spider,crawl,jeeves,yahoo,slurp" />! ! <cfloop index="localVars.item" list="#localVars.botList#">! ! <cfif FindNoCase(localVars.item, CGI.HTTP_USER_AGENT)>! ! ! <cfset localVars.findBot = true />! ! </cfif>! </cfloop>! ! <cfif NOT localVars.findBot>! ! Continue with error handler… ! </cfif>
  • 16. ErrorHandler.cfm - Use for both cferror and cfcatch ! • By coding the error handler to be available for use in a try/catch block we can drop it into places in the code where we are having trouble debugging what is happening, to get more information on the error. ! • This is particularly useful in CFC methods, where the global error handler won’t have any data about the local vars. ! • The error structure we receive for global errors versus inside a cfcatch is different. ! • We need to detect these and set up variables for the areas in the code where we are going to be outputting the error data. ! • When used in a cfcatch block, we may want to skip parts of the error handler, such as displaying a user-friendly error message. ! !
  • 17. ErrorHandler.cfm - Use for both cferror and cfcatch ! <cfif isDefined("error.Diagnostics")>! ! <cfset localVars.errormess = error.Diagnostics>! ! <cfset localVars.errorData = error>! ! <cfparam name="request.errorType" default="fatal" >! <cfelseif isDefined("cfcatch.message")>! ! <cfset localVars.errormess = cfcatch.message>! ! <cfset localVars.errorData = cfcatch>! ! <cfparam name="request.errorType" default="error" >! </cfif>! !
  • 18. ErrorHandler.cfm - Skip Common Errors ! • For some sites, you may have errors that you wish to detect due to them occurring frequently and not being fixable. ! • How you handle them may vary based on your environment and other detection methods for your sites (up-time detection, etc.) ! • For instance, for one client we frequently have database issues where lots of timeout errors get thrown regularly. This is a known issue the client has decided not to address at the time so while we log the number of times and pages they occur on, we don’t need to receive emails for them. ! • We also ran into a bug where a malformed returnFormat in an Ajax call to a CFC throws an error that can not be handled via other methods. ! !
  • 19. ErrorHandler.cfm - Skip Common Errors ! ! ! <cfset localVars.errorExcludeList = "Execution timeout expired,request has exceeded the allowable time limit,Invalid returnFormat: jsPr”/>! ! <cfloop index="localVars.item" list="#localVars.errorExcludeList#">! ! <cfif isDefined("error") AND FindNoCase(localVars.item, error.diagnostics)>! ! ! <cfset localVars.findExclude = true />! ! <cfelseif isDefined("cfcatch") AND FindNoCase(localVars.item, cfcatch.message)>! ! ! <cfset localVars.findExclude = true />! ! </cfif>! </cfloop>
  • 20. ErrorHandler.cfm - What to Include ! • What scopes you include will depend on your site and what types of activities ColdFusion is doing. ! • We will also need to set up a list of “secure” variables that we are going to want to exclude! • If you want to scrub the data for sensitive data, typically you will want to also create a list of scopes to scrub.! !
  • 21. ErrorHandler.cfm - What to Include ! localVars.varstodump=“CFCATCH,ERROR,APPLICATION,ARGUMENTS, ATTRIBUTES,CALLER,CGI,CLIENT,CFHTTP,FILE,FORM,REQUEST, SESSION, COOKIE,THIS,THISTAG,URL,VARIABLES";! ! localVars.varstoscrub=“ATTRIBUTES,ARGUMENTS,CGI,FORM,REQUEST, SESSION,URL,VARIABLES,COOKIE,CFCATCH,ERROR";! ! localVars.securevars=“CFID,CFTOKEN,JSESSIONID,SessionID,URLToken, password,newpassword,customerID,ccName,ccNumber,cvv2,encryptkey";! !
  • 22. ErrorHandler.cfm - Creating the Error Dumps ! • Now that we have our list of variables we want to output in our error logs and/or emails, we’ll loop over the list and dump each scope. ! • We will do some special handling for some scopes. This will include those that we list as potentially having secure information and scopes like Application that may have data like a bean factory that we don’t want to output in error messages. ! • Your application may have specific error scopes that have their own special handling. For instance, we set encrypted cookies for things like the customer ID on the site. For the error handler, I decrypt that string so that I have the actual customer ID to look up info in the database. Another example might be if I want to use the shopping cart ID to include a dump of the actual shopping cart contents in the emails. ! !
  • 23. ErrorHandler.cfm - Creating the Error Dumps <cfsavecontent variable="localVars.dataDump">! ! ! ! <cfloop list="#localVars.varstodump#" index=“localVars.loopItem">! ! ! ! ! ! Code to parse and dump out the variable scopes here!! ! ! </cfloop>! ! </cfsavecontent>! ! !
  • 24. ErrorHandler.cfm - Checking for CFC methods ! • One thing I always want to exclude from error dumps are user-defined functions and components.! • If you use a bean factory like Coldspring or Wirebox, it’s usually just an easy matter of excluding it in the appropriate scope dump. ! • If however, you have a collection of components and/or functions in something like Application scope you may need to manually exclude it.! • For components, you can use IsCFC() on CFLib.org written by Nathan Dintenfass.! • For user-defined (or built-in) functions, use IsFunction() also on CFLib.org, written by Ray Camden. ! • You can also use the showUDFs attribute on the cfdump tag itself. ! !
  • 25. ErrorHandler.cfm - Sample Dump for Application Scope ! <cfif IsDefined("#localVars.loopItem#") AND localVars.loopItem IS “APPLICATION">! <cfset localVars.ApplicationVars = StructNew()>! <cfset localVars.listExclude = "blogCache,errorLog" />! <cfloop item="localVars.each" collection=“#Application#">! <cfif NOT IsCFC( Application[localVars.each] ) AND NOT ! ! ! ListFindNoCase(localVars.listExclude, localVars.each)>! <cfset localVars.ApplicationVars[localVars.each] = Application[localVars.each]>! </cfif>! </cfloop>! ! <cfset request.cfdumpinited=“false”>! <cfdump var="#localVars.ApplicationVars#" label=“Application" showUDFs=“false”>
  • 26. ErrorHandler.cfm - Sample Dump to Scrub Scopes <cfelseif IsDefined("#localVars.loopItem#") AND ListFind(localVars.varstoscrub,localVars.loopItem)>! <cfset localVars.ScrubbedVars = structNew()>! <cfset localVars.scopeToCheck = Evaluate(localVars.loopItem) />! <cfloop item="localVars.each" collection="#localVars.scopeToCheck#">! <cfif ListFindNoCase(localVars.securevars,localVars.each)>! <cfset localVars.ScrubbedVars[localVars.each] = "removed">! ! ! ! ! <cfelse>! <cfset localVars.listremove = "GeneratedContent,CFCatch,CFError,Error,localVars,IsCFC">! <cfif NOT ListFindNoCase(localVars.listremove,localVars.each) ! ! AND NOT IsCFC(localVars.scopeToCheck[localVars.each]) ! ! AND NOT structKeyExists(localVars.ScrubbedVars, localVars.each)>! <cfset localVars.ScrubbedVars[localVars.each]= localVars.scopeToCheck[localVars.each]>! </cfif>! </cfif>! </cfloop>! <cfset request.cfdumpinited=“false”>! <cfdump var="#localVars.ScrubbedVars#" label="Scrubbed #localVars.loopitem#” showUDFs=“false”>
  • 27. ErrorHandler.cfm - Dump Remaining Scopes <cfsavecontent>! <cfloop … >! <cfif … >! Scrubbed var scopes! <cfelseif IsDefined("#localVars.loopItem#")>! <cfset request.cfdumpinited=“false”> ! <cfdump var="#localVars.ScrubbedVars#" label=“#localVars.loopitem#” showUDFs=“false”>! </cfif>! </cfloop>! </cfsavecontent>!
  • 28. ErrorHandler.cfm - Error Summary <cfsavecontent variable="localVars.basicinfo">! <cfoutput>! <table width="100%" cellpadding="5" cellspacing="0" border="0">! <cfloop collection="#localVars.errorData#" item="localVars.i">! <cfset localVars.data = localVars.errorData[localVars.i]>! <cfif IsSimpleValue(localVars.data) AND localVars.i IS NOT "GeneratedContent">! <tr><td>! <strong>#Ucase(localVars.i)#:</strong><br/>#localVars.data#! </td></tr>! </cfif>! </cfloop>! </table>! </cfoutput>! </cfsavecontent>
  • 29. ErrorHandler.cfm - Swap Settings for Error Type <cfswitch expression="#request.errorType#">! <cfcase value="init">! <cfset subject = "Error starting up #cgi.server_name#">! <cfset errorMessage = "#cgi.server_name# was not able to start up.”>! <cfset toAddr =“webmaster@cfwebtools.com" />! </cfcase>! <cfdefaultcase>! <cfset subject = "Error on #cgi.server_name#">! <cfset errorMessage = "An error has been encountered on #cgi.server_name#:”>! <cfset toAddr = "errors@cfwebtools.com">! </cfdefaultcase>! </cfswitch>!
  • 30. ErrorHandler.cfm - Eliminating Duplicate Errors • We don’t need to get many copies of the same error via email! • This makes it a lot harder to not only get an idea of how many different errors we have to review, but takes time opening and loading each email to see if it is unique. ! • There’s different ways you can handle this but the easiest is to just log each error in the application scope and then check it before adding new errors. ! • Typically I log each error only once every 4 hours, but you can use longer time frames based on tracking multiple errors as follows. ! • By keeping a count of the errors we can check if multiple copies of the error are being thrown. This can alert us to a critical situation on the server that may need to be addressed immediately. ! • I also typically use this with some of the errors that are common and I don’t need to get emails for single instances. ! • So we also want to track the number of times each error has been thrown in order to generate an email every X number of times (I use 25).
  • 31. ErrorHandler.cfm - Eliminating Duplicate Errors <cfif NOT StructKeyExists(Application.ErrorLog, localVars.Errormess) ! ! OR DateCompare( Application.ErrorLog[ localVars.Errormess ].TimeError, ! ! DateAdd("h", -4, Now() ) ) LT 0 >! ! Generate Error Dumps Email here….! <cfif request.errorType IS NOT "init">! ! ! ! ! <cfset Application.ErrorLog[localVars.Errormess] = TimeError: Now(), Count: 1 } />! </cfif>! <cfelse>! <cfset Application.ErrorLog[localVars.Errormess].Count++ />! <cfif Application.ErrorLog[localVars.Errormess].Count MOD 25 EQ 0>! Generate Multiple Errors Email here….! </cfif>! </cfif>
  • 32. ErrorHandler.cfm - Sample Email <cfif NOT localVars.findExclude>! <cfmail to="#toAddr#" from=“no-reply@cfwebtools.com“! subject="#subject#" type="HTML">! <br/><br/>! #errorMessage#<br/><br/>! #localVars.basicinfo#<br/><br/>! <strong>Full message:</strong><br/><br/>! #localVars.dataDump#<br/><br/>! </cfmail>! </cfif>
  • 33. ErrorHandler.cfm - Sample Multiple Errors Email <cfmail to="#toAddr#" from=“no-reply@cfwebtools.com“! subject=“MULTIPLE ERRORS ON #subject#" type="HTML">! <br/><br/>! The following error has occurred #Application.ErrorLog[localVars.errormess].Count# times in the last four hours on #cgi.server_name#:! #errorMessage#<br/><br/>! #localVars.basicinfo#<br/><br/>! <strong>Full message:</strong><br/><br/>! #localVars.dataDump#<br/><br/>! </cfmail>
  • 34. ErrorHandler.cfm - Show User Friendly Error Page • Based on the error type, we may or may not need to display a message to the user (for instance, error in a try/catch block we most likely will not)! • We will first try to display a page using the full site template. ! • If that page itself errors out though, we should have a very simple HTML only error page available as a fallback. ! • We also include analytics on the page itself to keep counts of different types of errors encountered.
  • 35. ErrorHandler.cfm - Show User Friendly Error Page <cfif NOT ListFind("email,cfcatch", request.errorType)>! <cftry>! ! <cfset action = "cferror">! ! <cfinclude template="/controller/linkcontroller.cfm" />! <cfabort>! ! <cfcatch type="any" >! <cfinclude template="displayerror.cfm">! <cfabort>! </cfcatch>! </cftry>! </cfif>
  • 36. ErrorHandler.cfm - Using in Try/Catch Blocks • The error handler will be used automatically for any unhanded CF errors. ! • However, one issue is that errors that occur inside CFCs will not include the local scoped variables. ! • Therefore, you may want to use the error handler inside a try/catch block particularly if you are trying to debug a specific error and need a copy of the local variables. ! • In order to see what the local vars are set to at the time of the error, you will need to copy them to another scope prior to calling the error handler. ! • We also use the error handler to notify us if there is some issue with application initialization.
  • 37. ErrorHandler.cfm - Using in Try/Catch Blocks function name…. {! try {! code here that we need to debug….! } catch (any err) {! ! //copy our local scope to request! ! request.functionLocal = Duplicate(local);! ! include “/views/errors/errorhandler.cfm”;! }! }!
  • 38. Tracking User Actions - Page Tracker • One thing that the error handler does not tell us is what the user might have done to cause the error. ! • We only know what happened at best for that request, but there are times when we may want to know the other actions the user performed prior to the error. ! • This can be particularly useful for errors thrown by Ajax requests, where we at least want to know the page there user was on and what they did to generate the Ajax call.! • Since our application already makes use of sessions, it makes sense to log the page requests into the session so that they automatically show up in the error handler. ! • We also include this session object into support emails since users typically do not include detailed information about what they were doing when they ran into a problem.
  • 39. Tracking User Actions - Page Tracker function onSessionStart() {! ! //initialize the page tracker! ! session.pageTracker = arrayNew(1);! }
  • 40. Tracking User Actions - Page Tracker function onRequestStart() {! request.thisPage = cgi.script_name & '?' & cgi.query_string;! if ( !arrayLen(session.pageTracker) IS 0 OR ! ! ! session.pageTracker[1] IS NOT request.thisPage ) {! ! lock scope="session" type="exclusive" timeout="10" {!! ! ! ! if ( arrayLen(session.pageTracker) LT 20 ) {! arrayPrepend(session.pageTracker,request.thisPage);! } else {! arrayDeleteAt(session.pageTracker,arrayLen(session.pageTracker));! arrayPrepend(session.pageTracker,request.thisPage);! }! }! }! }
  • 41. Tracking User Actions - User Info • If you use sessions, you might find it useful to load data into the session that can help you debug.! • For instance, we typically put the user email, customer ID, and name into the session when user logs in, even though this information is not otherwise used from the session scope. ! • This not only helps in cases where we need to review related customer data that might have caused the problem but that way we can also contact the customer once we have corrected the customer. Nothing impresses your users more than actually getting an email from your site telling them the problem they ran into when they were trying to shop has been fixed! ! • We also include this session information into support emails that get sent from the site, again since users have a tendency to do things like mistype their email if we ask them to enter it.
  • 42. BugLogHQ • BugLogHQ is a free, open source CFML tool to centralize the handling of bug reports for multiple applications. ! • It allows you to view, search, graph, report, and subscribe to bugs from your applications. ! • However, BugLogHQ does not include all the variable scopes that my global error can send out. ! • It does not typically include any scrubbing of the error data for possible secure items.! • Also, if you are sending every single error to it, you can overwhelm the database with error entries, particularly if you are working with an application that generates large numbers of errors, or cause an repetitive bug in development.
  • 43. BugLogHQ - Features • BugLogHQ has a powerful Rules feature to set up email notifications of errors, which include different rule types such as only the FirstInstance of an error, specific error messages, or daily summaries of errors. ! • We find this particularly useful for clients where we often use different developers on tasks, so that they can turn error reporting on and off as needed. ! • You can also set BugLogHQ to purge its errors on a regular basis. ! • BugLogHQ can also run “heartbeat” monitors to check that your website is running properly.
  • 44. BugLogHQ - Installation • Software and documentation found at http://www.bugloghq.com. ! • Runs on CF 8+ or Railo and mySQL or SQL Server. ! • Errors can be sent to BugLog using web service, HTTP post, or CFC call. ! • Includes clients for ColdFusion, Python, PHP and Javascript! ! Application.cfc - onApplicationStart() :! application.bugLogService = ! ! createObject(“component", “buglog.client.bugLogService”).init(! ! bugLogListener = ‘http://buglog:8080/listeners/bugLogListenerREST.cfm’);! ! ! ! ! !
  • 45. BugLogHQ - Usage in Error Handler • To send all our variable scopes to BugLog, we need to have a single object to include in the web service call. ! • Since BugLog already includes the error or cfcatch data, we don’t need to include those.! • We can also include an error type, which can be used as a filter in the BugLogHQ reports.! • I like to log even the errors that I typically don’t email on the first instance, so that I still have some idea how often those are occurring.
  • 46. BugLogHQ - Copying Variable Scopes localVars.strScopes = structNew();! ….! <cfdump var="#localVars.ScrubbedVars#" label="Scrubbed #localVars.loopitem#">! <cfif NOT ListFind(“ERROR, CFCATCH”, localVars.loopitem)>! <cfset localVars.strScopes[localVars.loopitem] = localVars.ScrubbedVars />! <cfelse>! <cfset localVars.errorData = localVars.ScrubbedVars>! </cfif>! …! <cfdump var="#Evaluate(localVars.loopItem)#" label="#localVars.loopItem#">! <cfset localVars.strScopes[localVars.loopitem] = Evaluate(localVars.loopItem) />!
  • 47. BugLogHQ - Logging the Error <cfif NOT localVars.findExclude>! ! … mail the error as usual! </cfif>! <!—- we check to make sure the bug log service is available (local dev) —->! <cfif structKeyExists(application,"bugLogService")>! <cfset application.bugLogService.notifyService(! ! ! ! localVars.errormess, ! ! ! ! localVars.errorData, ! ! ! ! localVars.strScopes, ! ! ! ! request.errorType)>! </cfif>
  • 48. Debugging Javascript Errors • Today’s applications typically have considerable javascript running on them! • jQuery, Bootstrap, AngularJS, and other libraries make sites more feature rich and user friendly, but harder to debug remote client issues. ! • How then can we figure out what the cause of a user’s issue is when we can’t see the Javascript error thrown by their browser? ! • BugLogHS does include a JS client but you will need to include it into your JS code. ! • There are a variety of excellent 3rd party services you can use for logging and tracking JS bugs.
  • 49. Javascript Error Reporting Tools • trackjs.com! • qbaka.com! • errorception.com! • jslogger.com! • muscula.com! • exceptionhub.com! • jserrlog.appspot.com (OSS)! • github.com/occ/TraceKit
  • 50. Mobile Error Monitoring Tools These can be used to monitor and track mobile device errors. ! • bugsense.com! • bugsnag.com
  • 51. BrowserHawk • BrowserHawk is an Enterprise-level tool for testing client environments for requirements for your websites or website features.! • It includes both a web service, and a JAR you can install on the server, to use in ColdFusion pages to test and/or log information about the client environment. ! • They also have a Javascript logging tool which works via webservice. ! • We have used BrowserHawk not just for testing compatibility for our site, but to check for search bots prior to generating errors, as well as including data about the client in support emails.