<!---
Purpose: To provide different means of handling error in a generic way for CFMX 6.1
Attributes:
type="custom | database | any | application | lock | template | security | object | expression | normal | missinginclude" -default "normal"
sendEmail="yes | no" -default no
message="[some error message to be displayed]" -default "No error message specified." -notes Should only be specified when having a "normal" type error
additionalDetail="[some error detail to be displayed]" -default "No additionalDetail specified."
debug="yes|no" -default "no"
to="[email address to send email to]" -default "errors@my-site-here.com"
from="[from email address]" -default "#application.applicationname#.errors@my-site-here.com"
errorfile="#errorfile#" -defualt errorfile.cfm
Usage Notes:
if installed under custom tags directory:
<cf_errorHandler [type="custom|database|any|application|lock|template|security|object|expression|normal|missinginclude"] [sendEmail="yes|no"] [message="#somemessage#"] [details="#somedetails#"] [url="#url"] [debug="yes|no"]>
if installed in relative directory to your application:
<cfmodule template="#path#/errorHandler.cfm" [type="custom|database|any|application|lock|template|security|object|expression|normal|missinginclude"] [sendEmail="yes|no"] [message="#somemessage#"] [details="#somedetails#"] [url="#url"] [debug="yes|no"]>
if this custom tag has thesame name as another tag in custom tags directory:
<cfmodule name="#dir#.#dir2#.errorHandler"[type="custom|database|any|application|lock|template|security|object|expression|normal|missinginclude"] [sendEmail="yes|no"] [message="#somemessage#"] [details="#somedetails#"] [url="#url"][debug="yes|no"]>
--->
<!--- Set default values on attributes --->
<cfparam name="attributes.sendEmail" default="no">
<cfparam name="attributes.message" default="No error message specified.">
<cfparam name="attributes.additionalDetail" default="No additionalDetail specified.">
<cfparam name="attributes.type" default="normal">
<cfparam name="attributes.debug" default="no">
<cfparam name="attributes.errorfile" default="">
<cfparam name="attributes.sourcefile" default="unknown">
<cfparam name="attributes.to" default="errors@my-site-here.com">
<cfparam name="attributes.errorTemplate" default="No error template specified.">
<!--- offending app --->
<cftry>
<cfset appName = Application.ApplicationName>
<cfcatch>
<cfset appName = "">
</cfcatch>
</cftry>
<!--- create a unique id for each error; based on appName timestamp random num --->
<cfset errorID = appName & "_">
<cfset errorID = errorID & DateFormat(now(), "yyyy-mm-dd") & "_">
<cfset errorID = errorID & TimeFormat(Now(), "hh-mm-ss-l") & "_">
<cfset errorID = errorID & RandRange(1,9999)>
<!--- if it's a custom error type (like cfthrow), then create variables differently --->
<cfif attributes.type IS "custom">
<!--- get template and message from caller --->
<cfset errorTemplate = attributes.errorTemplate>
<cfset errorLine = "???">
<cfset errorMsg = attributes.message>
<cfelse>
<!--- get offending template and line --->
<cftry>
<!--- look at the rootcause level first --->
<cfset errorTemplate = Caller.CFCatch.rootcause.tagContext[1].template>
<cfset errorLine = Caller.CFCatch.rootcause.tagContext[1].line>
<cfcatch>
<cftry>
<!--- then check above that, for when the error type is "Template" --->
<cfset errorTemplate = Caller.CFCatch.tagContext[1].template>
<cfset errorLine = Caller.CFCatch.tagContext[1].line>
<cfcatch>
<cfset errorTemplate = "tagContext[1].template couldn't be captured">
<cfset errorLine = "tagContext[1].line couldn't be captured">
</cfcatch>
</cftry>
</cfcatch>
</cftry>
<!--- get error message --->
<cftry>
<!--- look at the rootcause level first --->
<cfset errorMsg = Caller.CFCatch.rootcause.message>
<cfcatch>
<cftry>
<!--- then check above that, for when the error type is "Template" --->
<cfset errorMsg = Caller.CFCatch.message>
<cfcatch>
<cfset errorMsg = "error message couldn't be captured">
</cfcatch>
</cftry>
</cfcatch>
</cftry>
<!--- /check for custom type --->
</cfif>
<!--- check if application name exist --->
<cfif Len(appName)>
<cfset tmpStr = "#appName#.">
<cfelse>
<cfset tmpStr = "">
</cfif>
<cfparam name="attributes.from" default="#tmpStr#errors@my-site-here.com">
<!--- needed to support fusebox --->
<cfif isDefined("CALLER.dsn")>
<cfset dsn = CALLER.dsn>
<cfelseif isDefined("ATTRIBUTES.dsn")>
<cfset dsn = ATTRIBUTES.dsn>
<cfelse>
<cfset dsn = "UNDEFINED!!">
</cfif>
<!--- Make sure no garbage was given as a value for the type attribute. --->
<cfswitch expression="#lcase(attributes.type)#">
<cfcase value="normal,any,application,database,expression,missinginclude,template,object,security,lock,custom" delimiters=",">
</cfcase>
<cfdefaultcase>
<cfset variables.subtype = attributes.type>
<cfset attributes.type = "unknown">
</cfdefaultcase>
</cfswitch>
<cfsavecontent variable="errorText">
<cfoutput>
<strong>Template:</strong><br>
#errorTemplate# (line: #errorLine#)<br>
<strong>Message:</strong><br>
#errorMsg#<br>
<strong>Additional Details:</strong><br>
#attributes.additionalDetail#<br>
<strong>Type:</strong><br>
#attributes.type#<br>
<strong>DSN:</strong><br>
#dsn#<br>
<strong>Date of error:</strong><br>
#DateFormat(now(), "mm/dd/yyyy")#<br>
<strong>Time of error:</strong><br>
#TimeFormat(now(), "hh:mm:ss")#<br>
<strong>errorID:</strong> #errorID#<br>
<br>
</cfoutput>
<!--- loop through the application structure (if it exits) and print out the variables --->
<u>Application variables:</u><br>
<cfif IsDefined("APPLICATION") AND IsStruct(APPLICATION) AND StructCount(APPLICATION)>
<cfloop collection="#application#" item="itm">
<cfif IsObject(application[itm]) OR IsStruct(application[itm])>
<!--- <cfdump var="#application[itm]#"> --->
<cfoutput>
<strong>#itm#</strong>: StructCount (#StructCount(application[itm])#)<br>
</cfoutput>
<cfelse>
<cfoutput>
<strong>#itm#</strong>: #application[itm]#<br>
</cfoutput>
</cfif>
</cfloop>
<cfelse>
None Defined
</cfif>
<!---
<cftry>
<cfdump var="#Exception#" label="Exception" expand="true">
<cfcatch>couldn't dump Exception<br></cfcatch>
</cftry><br>
<br> --->
<!--- only try this dump if Caller.CFCatch is available --->
<cfif IsDefined("Caller.CFCatch")>
<cftry>
<br>
<cfloop collection="#Caller.cfcatch#" item="i">
<cfset data = StructFind(Caller.cfcatch, i)>
<cfif IsSimpleValue(data) AND (Not i CONTAINS "stacktrace")>
<cfoutput><strong>#Ucase(i)#</strong> = #data#<br></cfoutput>
</cfif>
</cfloop>
<cfset tagContextInfo = "">
<!--- loop thru array of templates and stick it into a comma-delimited list --->
<cfloop index="i" from="1" to="#ArrayLen(Caller.CFCATCH.TAGCONTEXT)#">
<cfset stCurrent = Caller.CFCATCH.TAGCONTEXT[i]>
<cfset tagContextInfo = tagContextInfo & "ID: " & stCurrent["ID"]>
<cfset tagContextInfo = tagContextInfo & "<br> LINE: " & stCurrent["LINE"]>
<cfset tagContextInfo = tagContextInfo & "<br> TEMPLATE: " & stCurrent["TEMPLATE"] & "<br><br>">
</cfloop>
<cfoutput>
<br>
<strong><u>Tag Context:</u></strong><br>
#tagContextInfo#
</cfoutput>
<cfcatch>couldn't dump Caller.CFCatch</cfcatch>
</cftry><br>
<br>
<!--- TODO: implement this CF hot fix, so the code below can run:
http://www.adobe.com/cfusion/knowledgebase/index.cfm?id=1a9c83c
<cftry>
<cfdump var="#Caller.CFCatch#" label="Caller.CFCatch" expand="true">
<cfcatch>couldn't dump Caller.CFCatch</cfcatch>
</cftry><br>
<br> --->
</cfif>
<cftry>
<cfdump var="#Client#" label="Client" expand="true">
<cfcatch>couldn't dump Client scope<br></cfcatch>
</cftry><br>
<br>
<!--- since we use FB, and use the attributes scope liberally, dump it --->
<cftry>
<cfdump var="#Caller.attributes#" label="Caller.attributes" expand="true">
<cfcatch>couldn't dump Caller.attributes scope<br></cfcatch>
</cftry><br>
<br>
<cftry>
<cfdump var="#Form#" label="Form" expand="true">
<cfcatch>couldn't dump Form scope<br></cfcatch>
</cftry><br>
<br>
<cftry>
<cfdump var="#URL#" label="URL" expand="true">
<cfcatch>couldn't dump URL scope<br></cfcatch>
</cftry><br>
<br>
<cftry>
<cfdump var="#CGI#" label="CGI" expand="true">
<cfcatch>couldn't dump CGI scope<br></cfcatch>
</cftry><br>
<br>
<cftry>
<cfdump var="#Cookie#" label="Cookie" expand="true">
<cfcatch>couldn't dump Cookie scope<br></cfcatch>
</cftry><br>
<br>
<cftry>
<cfdump var="#Session#" label="Session" expand="true">
<cfcatch>couldn't dump Session scope<br></cfcatch>
</cftry><br>
<br>
</cfsavecontent>
<!--- Sends the email with all of the approriate info to the administrator --->
<cfif Trim(attributes.sendEmail) is "yes">
<cfmail to="#attributes.to#"
from="#attributes.from#"
subject="An error has occurred; ID: #errorID#"
timeout="900"
type="HTML">
#errorText#
</cfmail>
</cfif>
<!---
if debug is set to yes just throw all pertinent info to the screen; otherwise forward to
customized error file
--->
<cfif attributes.debug eq "yes">
<cfoutput>#errorText#</cfoutput>
</body>
</html>
<cfelse>
<cfif attributes.errorfile NEQ "">
<cf_location url="#attributes.errorfile#" addtoken="false">
</cfif>
</cfif>