Wish List
Tags
adobe air ajax coldfusion examples ext flex javascript max2007 misc technology ui
Recent Entries
Search
RSS
Subscribe
What Function Called My Function
I read a post on the Adobe forums by Spike H asking:
I have written a utility component (test1 below) and want to keep track of what external functions call the functions within my component. Other programmers create a component (e.g. test2 below) that extends my utility component and then their functions call my functions. I want to record metric data to determine how much use my functions are getting and from where. I've used the getMetaData() function inside my functions, but that only gives me the name of the component that extends my component (in this case test2), not the specific function that called my function (in this case functionAtest2).
That piqued my interest, I figured there had to be a way to be able to find out what function called a specific function within a component. I know when we get an error you also get a stack dump which tells you the entire call stack so it is available sometimes (getting warmer). In ColdFusion when we do error handling there is also a cfcatch variable called tagContext that contains an quasi call stack (looking better). So that means that we need to have access to the tagContext, and as far as I know it is only available when an error occurs, so lets cause one (now we are cooking!).
What we will do then in order to achieve our purpose is create a utility function that forces an error, at the same time we will wrap the
The entire component looks something like this:
<cffunction name="functionToCall" returntype="void">
<cfoutput>called from #calling()#<br></cfoutput>
</cffunction>
<cffunction name="calling" output="true" returntype="string">
<cftry>
<cfthrow type="Application">
<cfcatch type="any">
<!--- the current template is always the template that actually does the calling, since this cfc is extended the current template
will be the template that extended this component --->
<cfset thispage = getcurrenttemplatepath()>
<!--- I put the tag context in a local variable not exactly necessary but ... --->
<cfset variables.tagcontext= cfcatch.tagContext>
<cfloop from="1" to="#arraylen(variables.tagcontext)#" index="i">
<cfif variables.tagcontext[i].template eq thispage>
<!--- return the calling function or store the information somewhere --->
<Cfreturn #mid(variables.tagcontext[i].raw_trace,findnocase("$func",variables.tagcontext[i].raw_trace)+5,(findnocase(".runFunction",variables.tagcontext[i].raw_trace)-(findnocase("$func",variables.tagcontext[i].raw_trace)+5)))#>
</cfif>
</cfloop>
</cfcatch>
</cftry>
</cffunction>
</cfcomponent>
I save the component as test.cfc and then created a second component (test2.cfc) that extends my first test component:
<cffunction name="callTheFunctionInSuper" returntype="void">
<cfset functionToCall()>
</cffunction>
<cffunction name="callTheCalling" returntype="void">
<cfset callTheFunctionInSuper()>
</cffunction>
</cfcomponent>
Just to make things a bit more interesting and to see how my example code handles the tagContext I created two functions. callTheCalling calls callTheFunctionInSuper which then calls functionToCall.
I then created a cfm page to actually do the calling.
mytest = createObject("component","com.gg.test1");
mytest.callTheCalling();
</cfscript>
And voila! The output looked like:


for load reasons I hope he remembers to add a switch to turn the metrics off when he's finished ...
PS: I can't help thinking that maybe an AOP approach (with ColdSpring) might be worthwhile here.