This question has come up a couple of times recently in support/pre-sales queries. Essentially the question is why can’t FusionReactor see the values of variables (eg LOCAL/VARIABLES/REQUEST scope etc)?
FusionReactor is a low-overhead Java production server monitor designed for light-weight 24×7 use. It let’s you see what’s happening on your server right now and the recent past. It has other features that can prevent a server from failing and alerting based on rule-sets etc but that’s out of the scope for this question. If you think about the tool, it really has to be very low overhead to not skew the metrics you’re seeing and be of high value. A page is typically processing and running through many lines of code per second – as that happens, variables are constantly being created and updated. If we were to try and show variables in FusionReactor, the variable would most likely have changed it’s value by the time you’ve read it. One option of course would be to stop processing until further input – but then we’d really be a step-debugger (let me introduce you to FusionDebug now – the first & fastest CFML step-debugger and the only one that works with both Adobe CF and Railo). Another would be to only show variable values at the end of a request, or perhaps when each query executes. If you’re interested in variable values at the end of the request, you’re probably debugging something. This is where a step-debugger would be useful or you can output the value to DB/file/screen. If you’re interested in variable values when a query executes, it’s probably because you want to know what query is going to be run – if that’s the case, you really should just wrap your datasource and have FusionReactor tell you the query (and it’s query params) along with other useful data (like how fast the DB query was, how quickly the resultset travelled over the network, how many rows were returned, etc).
The most worthwhile argument I’ve seen was to capture variable values at the time a request fails – but then this opens another question of what is a failed request? A server 500 error? Well what if you try/catch the error and give the user some other route to continue – how would FusionReactor know to capture the variable values?
Now we’ve dealt with the logical reasons why we should or should not have this feature, the next is to think about the technical overhead – reading, storing and managing these variable values would be very costly – in both execution time and memory. For example, what if your request has a 200MB file in memory? Should FusionReactor take a copy of that memory so that it can display/notify you of it? Of course, these are loaded questions but hopefully they start to explain why this feature isn’t present. However, read on because there’s a very simplistic way to see what you want…
FusionReactor supplies an API. One of the API methods provides a way of giving FusionReactor some information to store & display with the request details. It’s quite simple to include in your code and would let you easily push any information you want for display in FusionReactor. This is most commonly used for things like tracking long running functions (eg: consider a credit card authorization call in an e-commerce application)…
<cfset frapiClass = createObject("java", "com.intergral.fusionreactor.api.FRAPI") / <cfset frapi = frapiClass.getInstance() / !--- Note: The above two lines only need to be done once per request. You could put the variables into request scope and re-use multiple times. --- cfset frapi.trace( "Calling doCCAuth()..." ) / cfset ccAuthResult = doCCAuth(cardNumber, expiryDate, cvv) / cfset frapi.trace( "Completed doCCAuth. Result = #ccAuthResult#" ) / !--- Note: FusionReactor will automatically time-stamp the traces so you know how long the call has taken ---
Taking this idea, we can easily have FusionReactor display all our (simple) variables (eg with LOCAL scope):
<cfset frapiClass = createObject("java", "com.intergral.fusionreactor.api.FRAPI") / cfset frapi = frapiClass.getInstance() / cfloop collection="#LOCAL#" index="key" <cfset frapi.trace( "LOCAL.#key# = #LOCAL[key]#" ) / /cfloop
If your scope contains complex variables (query, array, struct, object, etc) then you could serialize them to JSON or provide a toString() method as preferred.