Getting custom instrumentation and metrics using FusionReactor: Examples with ColdFusion


FusionReactor will simply work out-of-the-box to give you masses of metric data and insight into requests, transactions, queries and resources without adding any additional code to your application.   However, if you want to get even more insight into specific areas of your application, then it’s easy to customize FusionReactor.   This level of customization will enable you to instrument specific parts of your code that FusionReactor (normally) does not track e.g. you can track method calls, web service calls – anything you like.   All this can be achieved by simply adding a few lines of code to instruct FusionReactor to track metrics, add properties to transactions or even create new child transactions around parts of your code.

In this post I will show you how to instrument your ColdFusion code to:

  • Create graphed series
  • Add properties to transactions
  • Create new Transactions

Creating a Graphed Series

The first step in creating a tracked series in FusionReactor is to create an instance of the FusionReactor API, playfully named FRAPI. This requires the use of the ColdFusion createObject call, see below.

Create FRAPI object
<cfset frapiObj = createObject("java", "com.intergral.fusionreactor.api.FRAPI")>
<cfset frapi = frapiObj.getInstance()>

From here all we need do is call the method on the frapi variable to post the metric, see below.

 

Post Float value
<cfset frapi.postNumericAggregateMetricFloat("/series/name", 10.0)>
 As ColdFusion can have some problems with distinguishing float and long primitive values there is also a method that takes a long, see below.
Post long value
 <cfset frapi.postNumericAggregateMetricLong("/series/name", 10)>
 Now both of these methods will take the value and post it to the given series name, in the event that that series does not exist it will be created automatically. These two methods will also create the standard numeric aggregates that are available in FusionReactor (1 Hour, 1 Day and 1 Week), if you do not want this much data from the series then you can use the alternative methods to post data without creating the aggregates.
Non Aggregated metrics
<cfset frapi.postNumericMetricLong("/series/name", 10)>
<cfset frapi.postNumericMetricFloat("/series/name", 10.0)>

The first call to post will create the series and aggregates, so if you first call is to postNumericAggregateMetric.. then the series will have the aggregates.  Similarly if you create the series using the postNumeric. then the series will not have the aggregates, even if a later post is to postNumericAggregate.

 

A Simple Example

Simulate Revenue being generated via sales and display the revenue in a graph within FusionReactor.

<cfloop from=1 to=120 index="j">
   <cfscript>
   frapi.postNumericAggregateMetric("/Revenue", RandRange(100,300));
   Thread.sleep(JavaCast("long",1000));
   </cfscript>
   <cfflush>
</cfloop>

Once you have posted the values to FRAPI you can see the graphs in FusionReactor on the Custom Metrics page. (Metrics -> Custom Metrics) and will be able to access the /Revenue values from the drop down menu.

FRAPI customization in FusionReactor

 

Add Properties to a Transaction

FusionReactor will automatically track lots of ColdFusion metrics, one of the most important is Web Requests. Along with tracking requests, FusionReactor is able to attach properties to requests so you can better diagnose problems later on. To attach a property to a transaction using ColdFusion see the code snippet below.

 

Adding properties to WebRequest
<cfset transaction = frapi.getActiveTransaction()>
<cfset transaction.setProperty("/property/name","StringValue")>

The setProperty method is effectively a map put, and is able to take any object as a value. However the FusionReactor UI is only able to display the value as a string, so it is a good idea to ensure the result of the toString method of the given object is a user friendly string.

It is even possible to use the FusionReactor as a kind of private session store, that is only available for the life time of that request. So similar as above, but by using the getActiveMasterTransaction you can always get the top level transaction on this request. The difference between getActiveMasterTransaction and getActiveTransaction is explained in the next section. With this top level transaction you can put and get properties from it just like a session, but this is only available for this request.

 

Get property from Transaction
<cfset transaction = frapi.getActiveMasterTransaction()>
<cfset prop = transaction.getProperty("/property/name")>

If you do put properties into the request it is important to remember that FusionReactor will keep these requests in memory for some time, depending on settings, so it is NOT ADVISABLE to put large objects into the request properties !

 

Creating new Transactions

As mentioned above, FusionReactor will automatically create many transactions to track WebRequests, JDBC requests, CFHTTP among many more.  Let’s imagine you have a function or section of code that you want to track the performance of.   Using FusionReactor you can wrap this section of code is a custom transaction to visualize the performance inside FusionReactor.   Doing this is very simple, image we have the below CFFunction code.

 

Example CFFunction
<cffunction name="newRandomNumber" access="public" returnType="string" output="false">
<cfset rndObj = createObject("java", "java.util.Random")>
<cfset rnd = rndObj.init()>
<cfset area = rnd.nextInt(99999)>
<cfreturn area>
</cffunction>
 So from this example if we want to track all calls to this function all we need to is add a create and end transaction call.
Instrumented CFFunction
<cffunction name="newRandomNumber" access="public" returnType="string" output="false">
  <cfset frapiObj = createObject("java","com.intergral.fusionreactor.api.FRAPI")>
  <cfset frapi = frapiObj.getInstance()>
  <cfset trans = frapi.createTransaction("newRandomNumber")>
  <cfset rndObj = createObject("java", "java.util.Random")>
  <cfset rnd = rndObj.init()>
  <cfset area = rnd.nextInt(99999)>
  <cfset trans.close()>
  <cfreturn area>
</cffunction>

This code will now create a transaction with the flavour “newRandomNumber”, which will be added as a child transaction to the web request and visible in the FusionReactor UI. Alternatively there is a createTrackedTransaction method that will do the same as the createTransaction but will also create a periodic sampler that will produce a activity and duration graph for the given transaction flavour.

Summary

These three features of FRAPI are a small select sample of the functions available, and offer some unique and powerful options to developers that are looking for ways to track performance and debug code. There are many other methods available via the FRAPI interface many of which are helpful for both tracking performance and debugging errors. For more information on the available methods please review the Java docs.

Comments are closed.