A reader asks:
Ray, I am in the process of revamping how we handle errors, especially with the new onError event in Application.cfc. Most of the examples that I have seen use onError for logging errors to a file and then output some message to a user (as long as the event did not occur in onApplicationEnd or onSessionEnd). We do not want to log errors to a file, instead we would like to receive an email about the error and show the user a friendly error page. In this case, would we use onError or cferror or both? If both, what should onError handle before throwing the error to cferror? I am trying to find a best practice way of handling site-wide errors in the top level Application.cfc. Any help would be greatly appreciated!
This is actually quite simple. Your onError can use cfmail just as easily as it can use cflog. What I would suggest is something like this in your onError (assuming that you named the exception argument "exception"):
<cfmail to="your address here" from="your address here" subject="Error on Site X" type="html">
<cfdump var="#arguments.exception#">
<cfdump var="#arguments.cgi#">
<cfdump var="#arguments.form#">
<cfdump var="#arguments.url#">
</cfmail>
As you can see, all I'm doing is sending a dump of the exception, as well as the CGI, Form, and URL scopes. Many times these scopes will provide information about what was going on at the time of the error. You can also dump cookie, session, client, and application if you want. You can also be a bit "prettier" and use a nicely formatted table on top. Personally, I just like the dump as I can tell pretty quickly from it what the problem is.
Just to be clear - this isn't an "either or" type situation. You can mail and you can log and you can present a nice screen to the user.
Archived Comments
hey thats a good idea. I never thought of emailing the dump's like that.
nice call!
- D
Be careful with what scopes you dump, though. Depending on what information you store in session/application scopes (or whatever else you're displaying), it can easily create 1+ MB html emails (I know from expecience!)
Brian
Also, if you dump application or session, you would have to lock them wouldn't you ? If it's a big application that generates lots of these error, wouldn't it slow the sytem down to perform all these locks ?
It is only a read, so you wouldn't need to lock it.
You don't really want all that bloated HTML+CSS+JS table markup in an email... Dump the structs out to plain text. If there's not a UDF to do that on CFLIB, I'll have to upload mine. I wrote it specifically for this purpose and also to display the dumps in a textarea.
What's wrong Doug - you on dialup? ;)
Actually, that's not a horribly bad idea - "DumpLite" function. I may steal the idea and blog it one day. :)
I think the problem was really how the CSS and layout was screwing with my layout (creating a horizontal scrollbar and "breaking my template" by pushing everything on the right side off the screen as well). The same can happen with webmail readers as well. With tables, there is little fitting and wrapping to accomodate the size or the window/element/reader.
Just wanting to find out a value or existence of somthing, it's pretty easy to scan a list like I output:
SESSION = [Struct]
SESSION.CFTOKEN = XXXX
SESSION.URLTOKEN = CFID=YYYY&CFTOKEN=XXXX
SESSION.CFID = YYYY
SESSION.USER = [Struct]
SESSION.USER.FULLNAME = Doug
SESSION.USER.ROLES = [Array]
SESSION.USER.ROLES.1 = Super Llama
SESSION.USER.ROLES.2 = Janitor
SESSION.USER.USERNAME = dgibson
SESSION.USER.AUTHENTICATED = 1
I'll send the UDF to CFLIB.org and you can post or tidy it as needed.
when my users' sessions time out, all the session variables are cleared along with it and that's fine with me, but when the end user goes to the next page they get an ugly error about a session variable not being defined. how do I make all those cranky users happy?
Your code should handle cases where session variables don't exist. So for example, if your site has a logon system then your onRequestStart should look for session.username, and if it doesn't exist, log them in. I mean ask them to login.
I had code similar to that, but I was using the cflogin framework so coldfusion thought they were still logged in and didn't run that code so outside of the cflogin I added:
<cfif NOT StructKeyExists(Session,"UserName") or Session.UserName is "">
<cflogout>
</cfif>
and then right after that I start the cflogin code. works fine now, Thanks Ray!
That code seems to work well. However, would it not make sense to include the date and time that the error occurred as well?
I don't normally since the date/time will be darn close to the date/time on the mail itself.
Okay, so I did the above and got an error stating "Element CGI is undefined in ARGUMENTS." I guess I should check whether or not the variables are defined. Or, am I missing something?
My onError method is:
<cffunction name="onError" access="public" output="true">
<cfargument name="Exception" type="Any" required="true" />
<cfargument name="EventName" type="String" required="true" />
<cfif ARGUMENTS.Exception.RootCause.Type EQ "coldfusion.runtime.AbortException">
<cfreturn/>
</cfif>
<cfmail ... >
<p>Error Event: #ARGUMENTS.EventName#</p>
<cfdump var="#ARGUMENTS.exception#">
<cfdump var="#ARGUMENTS.cgi#">
<cfdump var="#ARGUMENTS.form#">
<cfdump var="#ARGUMENTS.url#">
</cfmail>
.
.
.
</cffunction>
It's not arguments.CGI, or arguments.url, or arguments.form. CGI, Form, and URL are built in scopes. So dump them by theselves.
<cfdump var="#cgi#" label="CGI">
<cfdump var="#form#" label="Form">
<cfdump var="#URL#" label="URL">
I know, bring up an old post but I was looking for some onError stuff.
You say no need to use "arguments.", but in your code in the blog post you specifically put that.
You don't HAVE to scope the variables, but I normally do scope them.