Yesterday Mike Henke asked an interesting question on Twitter. (And I should thank him as this is the second time now one of his tweets has led to an interesting discussion.) He wished there was a way to make a try/catch be disabled when testing. Obviously you wouldn't do this in production, but I think most folks could imagine needing to temporarily disable a try/catch so that you can see full details of an error. I decided to take a quick look into this and found something I thought was interesting.
First off - if you are willing to edit code, then you could just remove the try/catch. Another quick hack would be to use a conditional rethrow as in the pseudo-code below:
<cftry> <cf_dosomethingnaughty> <cfcatch> <cfif is notProduction> <cfrethrow> </cfif> <p>I'm so sorry you got an error. I really do care. Really.</p> </cfcatch> </cftry>
That's a manual approach and would work, but I had a hunch about an alternative that could possibly work as well. I remembered that exceptions show up when ColdFusion debugging is turned on. So I whipped up a CFM with an error in it wrapped in try/catch then loaded it. As expected, my error was hidden in the main display, and down in my debug area I could clearly see the exception:
So that may be good enough. But there isn't a lot of detail in there. I opened up the debug template and looked at how we gather the exception info:
<cfquery dbType="query" name="cfdebug_ex" debug="false"> SELECT * FROM qEvents WHERE type = 'Exception' </cfquery>
For the hell of it, I quickly added a cfdump and looked at the data. Guess what? The entire stack trace is there. The debug template simply doesn't use it. To be fair, they are kinda big, but I went ahead and modified the display code:
<!--- Exceptions ---> <cfif bFoundExceptions> <cftry> <cfoutput> <p class="cfdebug"><hr/><b class="cfdebuglge"><a name="cfdebug_exceptions">Exceptions</a></b></p> <cfloop query="cfdebug_ex"> <div class="cfdebug">#TimeFormat(cfdebug_ex.timestamp, "HH:mm:ss.SSS")# - #cfdebug_ex.name# <cfif FindNoCase("Exception", cfdebug_ex.name) EQ 0>Exception</cfif> - in #encodeForErrorSmart(cfdebug_ex.template)# : line #encodeForErrorSmart(cfdebug_ex.line)#</div> <cfif IsDefined("cfdebug_ex.message") AND Len(Trim(cfdebug_ex.message)) GT 0> <pre> #encodeForErrorSmart(cfdebug_ex.message)# </pre> <cfdump var="#cfdebug_ex.stacktrace#"> </cfif> </cfloop> </cfoutput> <cfcatch type="Any"> <!--- Error reporting an exception event entry. ---> </cfcatch> </cftry> </cfif>
Just to be sure it's clear - my modification is the cfdump. Here's a screen shot:
What do folks think about this approach? I know I've said it many times before, but do not forget that both the debug and exception templates are open source. You can hack them up - as I and others have done over the years. If you want to try this mod, just save the attached file to your WEB-INF/debug folder and select the filename "ray" in your ColdFusion Administrator settings.