4 Replies - 2123 Views - Last Post: 18 March 2011 - 07:04 AM Rate Topic: -----

#1 Craig328  Icon User is offline

  • I make this look good
  • member icon

Reputation: 1888
  • View blog
  • Posts: 3,427
  • Joined: 13-January 08

Odd CF Struct Behavior In CF9

Posted 17 February 2011 - 10:44 AM

It's not often one runs across something in CF these days that qualifies as an actual bug. This isn't one (I think) but I encountered this issue recently and wanted to post it up on the web somewhere so when others encounter it Google will have a reference to this post in the appropriate search results.

I've recently been tasked with building a centralized site error catcher for my employer. They have dozens of sites running on both CF8 and CF9 and they needed a way to collect all the errors from all the sites and funnel them to one database table collecting things like the site the error occurred on, form/session/URL/client variables in effect at the time of the error and, of course, the error content itself. To do this, I built code in each site's onerror method for each Application.cfc. As we know, the onerror method fires for each exception error generated on any sites using that Application.cfc. My plan was to collect the various bits of information I needed, drop them into a Coldfusion struct, serialize that struct into a WDDX string and then store the resultant string in the database. Later, calling up a particular error would require only that you grab the appropriate record from the database, deserialize the string from WDDX back into a struct and then CFDUMP that struct to the screen for the dev to examine. Understand, when building the struct initially, I am storing structs inside the error storage struct that I'm serializing. That is, I'm doing something like this:
<cfset errorStruct = StructNew()>
<cfset temp = StructInsert(errorStruct, "ErrorTime", Now())>
<cfset temp = StructInsert(errorStruct, "CGI", cgi)>
<cfset temp = StructInsert(errorStruct, "Error", arguments.exception)>
<cfset temp = StructInsert(errorStruct, "Form", form)>
<cfwddx action="cfml2wddx" input="#errorStruct#" output="errorString">


In case you didn't know, the onerror method in Application.cfc will generate an arguments variable (it is still, after all, a CF component method) called exception that will populate with the error structure that Coldfusion creates whenever an exception error occurs. So, on line 4, I'm dropping that CF generated error struct into my own structure (errorStruct) that I also store the CGI, form and other things in (the example isn't a line for line copy of what I'm doing).

Anyway, this encountered a problem for some errors wherein the string turned out to be too long (in my case, greater than the 64,000 characters I had allotted via the datatype for that column in the database table). I realized by wholesale saving the entire error scope that I was saving things I didn't really need: namely things like the StackTrace and objectType items found in the CF generated error struct. My idea was to remove those from the CF generated error struct before storing them in my custom errorStruct...and this is where I encountered the problem I'm writing about.

For reference, I'm using CF9 as illustrated by the dump of the server scope:
Posted Image

And for illustration purposes, I'm going to concentrate solely on StackTrace. The original CF generated error struct looked like this:
Posted Image

So, to get rid of stacktrace my first idea was to do a StructClear which when I tried it in the onerror method looked like this:
<cfset temp = StructClear(arguments.exception.stacktrace)>

And resulted in this:
Posted Image

No dice. So my next attempt was a StructDelete:
<cfset temp = StructDelete(arguments.exception,"stacktrace",true)>

Which did this:
Posted Image

Also no joy. So, StructClear and StructDelete both failed. My next thought was to overwrite stacktrace like so:
<cfset arguments.exception.stacktrace = "blorf">

Which, surprisingly, did nothing per the before and after CFDUMPS of the error struct (you should see "blorf" as the stacktrace content in the second dump):
Posted Image

Now, that didn't overwrite...but it also didn't generate an error. CF9 simply ignored it. By now, it's becoming obvious to me that CF9's error structure is something I'm not allowed to mess with...so naturally, I tried messing with it in one more way: I tried adding to it like so:
<cfset arguments.exception.testy = "this is way testy!">

And got the, by now, predictable result:
Posted Image

It didn't add it either...but it also didn't tell me it didn't. Again, it simply ignored me.

What does all this mean? It means that it appears that CF generated structs like error are pretty much "view only" and cannot be altered. This made me wonder if the same was true for the struct generated when you use CFTRY/CFCATCH and I found it had identical behavior to the error struct that I illustrated above.

In my case, I circumvented this issue by creating my own error struct in the onerror method and populating it only with the things I needed before adding it to my overall error struct and serializing it into a string. However, my looking through the online Adobe CF documentation doesn't mention that either error or cfcatch cannot be edited in any way by application code. What's worse, the error messages aren't exactly informative and in cases like editing an existing variable value or adding a new one, it doesn't tell you anything at all...it simply ignores you which is decidedly unhelpful behavior.

So, consider this post as a warning sign if you need to do more than simply read the contents of either the error or cfcatch structs generated by CF9. It doesn't appear to be possible.

I welcome comments or contrary test results. Please post them here.

Is This A Good Question/Topic? 0
  • +

Replies To: Odd CF Struct Behavior In CF9

#2 xheartonfire43x  Icon User is offline

  • D.I.C Regular

Reputation: 46
  • View blog
  • Posts: 454
  • Joined: 22-December 08

Re: Odd CF Struct Behavior In CF9

Posted 20 February 2011 - 07:32 AM

What you might want to look into is the new Kakapo application on RiaForge. It is a pretty slick error manager from what I have seen. I haven't had time to get it running myself, but I plan to use it in my next application. Basically in your onerror method of your Application.cfc you add a line of code that submits the error to Kakapo. Kakapo then stores the error in a database, and can even generate screenshots and emails.
Was This Post Helpful? 0
  • +
  • -

#3 CR250  Icon User is offline

  • D.I.C Head

Reputation: 3
  • View blog
  • Posts: 58
  • Joined: 14-June 08

Re: Odd CF Struct Behavior In CF9

Posted 16 March 2011 - 03:15 PM

Interesting.
Was This Post Helpful? 0
  • +
  • -

#4 xheartonfire43x  Icon User is offline

  • D.I.C Regular

Reputation: 46
  • View blog
  • Posts: 454
  • Joined: 22-December 08

Re: Odd CF Struct Behavior In CF9

Posted 18 March 2011 - 06:51 AM

Have you tried copying the exception into a new struct? It makes sense for a struct to be a java struct because it is Java that is actually causing the error.
Was This Post Helpful? 0
  • +
  • -

#5 Craig328  Icon User is offline

  • I make this look good
  • member icon

Reputation: 1888
  • View blog
  • Posts: 3,427
  • Joined: 13-January 08

Re: Odd CF Struct Behavior In CF9

Posted 18 March 2011 - 07:04 AM

View PostCraig328, on 17 February 2011 - 01:44 PM, said:

In my case, I circumvented this issue by creating my own error struct in the onerror method and populating it only with the things I needed before adding it to my overall error struct and serializing it into a string.



Yep. That was what I ended up doing and that works fine. With the benefit of hindsight I can see the reason why I couldn't edit or amend the CF generated structs. That said, CF9 runs on a Java engine so, in truth, all CF structs have some kind of base Java to them as it is. What's odd and isn't mentioned anywhere that I could see in Adobe's documentation is that, for whatever reason, whatever they use to generate the struct for ERROR and CFCATCH is different that what they use to generate a struct for other server generated structs like the SERVER and user generated scopes like application, session, client and so on.

Now, it could be a security measure to not allow manual changing of what ends up in the ERROR and CFCATCH scopes...but again, nothing in the docs say that. I'd understand if they didn't want code to have the ability to change the error message, the stacktrace or whatever else. That would make sense but they just don't bother to mention it is all.

So yeah, building your own is the way to go. In my case, I changed the architecture of the whole reporting system to utilize a web service call for all the sites to report to a single collecting site. The web service receives the error reports and saves the errors to a database for the dev team to examine later. It also makes it very handy to be able to do comprehensive error reporting across all our sites. Building our own struct and including only the pieces we need was a necessity.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1