CFWheels – logging the flash

One of the most useful features of CFWheels is ‘the Flash’.

Essentially, it’s a session scope which is designed to carry messages over page redirects, and only remove itself once it’s actually been viewed by the user.
I usually use it when a user has updated, deleted or requested something which requires some sort of feedback – like a password reset, a profile change etc.
Using filters, we can start using these flash scope messages as a basic logging device; did the user see an error message when they tried to update their profile? Was their password change successful? Were they told about it? etc.
In my Users.cfc controller, I’ve got one important line which makes this possible;

<cfset filters(through="logFlash", type="after")>

This means after any function in my Users.cfc controller is executed, logFlash() is called.

And in my Controller.cfc (where functions which may be required by all controllers live), I’ve got the two logging functions called logFlash, and addLogLine:

 
<cffunction name="logFlash" hint="Grabs the message in the flash scope and logs it">
<cfif structkeyexists(session.flash, "error")>
<cfset addLogLine(name=session.flash.error, type="error")>
</cfif>
<cfif structkeyexists(session.flash, "success")>
<cfset addLogLine(name=session.flash.success, type="success")>
</cfif>
</cffunction>

This function looks for struct keys of ‘error’ or ‘success’  in the flash scope and calls addLogLine() – this example creates a db row in a table called logfiles, but you could easily rewrite this to suit your needs (i.e email you, or write to a static file): I’m also logging the current userid, what type of message it was, and the calling IP address – plus I’m using createdAt in the logFiles table to automatically timestamp the entry.

 
<cffunction name="addLogLine" hint="Manually add a log line">
<cfargument name="name" required="yes" hint="The Actual Log Message">
<cfargument name="type" required="no" default="admin" hint="example options: public | admin | login | file | error | success">
<cfif NOT structkeyexists(session, "currentUser")>
<cfset thisuserid=0>
<cfelse>
<cfset thisuserid=session.currentUser.username>
</cfif>
<cfset logline=model("logfile").create(name=arguments.name, userid=thisuserid, 
type=arguments.type, ip=cgi.REMOTE_ADDR)>
<cfreturn true />
</cffunction>

Overall, a really useful way of working out what the user is seeing, and once you’ve set up these functions, calling them from other controllers is simply a matter of adding one line!