How to Parse (File, Package, Function Name) from a Stack Trace in ActionScript (AS3)

So stack traces can look different depending on the flash player in which it is running. For example in the Flash IDE standalone player a constructor will look like this ConstructorFunctionName$iinit() but in the player running in a web page it will just look like ConstructorFunctionName(). It is handy for debugging purposes to extract data like the FLA file name of the SWF, the package where the error has been thrown, the class where the error was thrown and the function where the error was thrown. 

//first thing that needs to be done is an error needs to be thrown, 
//this will give you a stack trace for the place where the error was thrown.
function test():void {
    var parsedData:Object;
    var stackTrace:String;
    //here is where the error is artificialy  thrown, 
    try {
        throw new Error("");
    } catch (e:Error) {
        stackTrace = e.getStackTrace();
    }
    parsedData = parseDataFromStackTrace(stackTrace);
    trace("fileName : "+parsedData.fileName);
    trace("packageName : "+parsedData.packageName);
    trace("className : "+parsedData.className);
    trace("functionName : "+parsedData.functionName);
}
test();

function parseDataFromStackTrace(stackTrace:String):Object {
    //extract function name from the stack trace
    var parsedDataObj:Object = {fileName:"",packageName:"",className:"",functionName:""};
    var nameResults:Array;
    //extract the package from the class name
    var matchExpression:RegExp;
    var isFileNameFound:Boolean;
    //if running in debugger you are going to remove that data
    var removeDebuggerData:RegExp;
    removeDebuggerData = /\[.*?\]/msgi;
    stackTrace = stackTrace.replace(removeDebuggerData,"");
    //remove the Error message at the top of the stack trace
    var removeTop:RegExp;
    removeTop = /^Error.*?at\s/msi;
    stackTrace = stackTrace.replace(removeTop,"");
    stackTrace = "at "+stackTrace;
    //get file name
    matchExpression = /(at\s)*(.*?)_fla::/i;
    nameResults = stackTrace.match(matchExpression);
    if (nameResults != null && nameResults.length > 2) {
        parsedDataObj.fileName = nameResults[2];
        parsedDataObj.fileName =  parsedDataObj.fileName.replace(/^\s*at\s/i,"")+".fla";
        isFileNameFound = true;
    }
    //match timeline data
    matchExpression = /^at\s(.*?)::(.*?)\/(.*?)::(.*?)\(\)/i;
    nameResults = stackTrace.match(matchExpression);

    if (nameResults != null && nameResults.length > 4) {
        if (!isFileNameFound) {
            parsedDataObj.fileName = String(nameResults[1]).replace(/_fla$/i,".fla");
            parsedDataObj.fileName = parsedDataObj.fileName.replace(/^at\s/i,"");
        }
        parsedDataObj.packageName = String(nameResults[1]);
        parsedDataObj.className = String(nameResults[2]);
        parsedDataObj.functionName = String(nameResults[4]);
    } else {
        //match function in a class of format com.package::SomeClass/somefunction()
        matchExpression = /^at\s(.*?)::(.*?)\/(.*?)\(\)/i;
        nameResults = stackTrace.match(matchExpression);
        if (nameResults != null && nameResults.length > 3) {
            if (!isFileNameFound) {
                parsedDataObj.fileName = String(nameResults[2])+".as";
            }
            parsedDataObj.packageName = nameResults[1];
            parsedDataObj.className = nameResults[2];
            parsedDataObj.functionName = String(nameResults[3]);
        } else {
            //match a contructor with $iinit
            matchExpression = /^at\s(.*?)::(.*?)\$(.*?)\(\)/i;
            nameResults = stackTrace.match(matchExpression);
            if (nameResults != null && nameResults.length > 3) {
                if (!isFileNameFound) {
                    parsedDataObj.fileName = String(nameResults[2])+".as";
                }
                parsedDataObj.packageName = String(nameResults[1]);
                parsedDataObj.className = String(nameResults[2]);
                parsedDataObj.functionName = String(nameResults[2]);
            } else {
                //match a contructor that looks like this com.package::SomeClassConstructor()
                matchExpression = /^at\s(.*?)::(.*?)\(\)/i;
                nameResults = stackTrace.match(matchExpression);
                if (nameResults != null && nameResults.length > 2) {
                    if (!isFileNameFound) {
                        parsedDataObj.fileName = String(nameResults[2])+".as";
                    }
                    parsedDataObj.packageName = String(nameResults[1]);
                    parsedDataObj.className = String(nameResults[2]);
                    parsedDataObj.functionName = String(nameResults[2]);
                } else {
                    //can't find a match - this is a catch all, you never know, 
                    //if you find situations where this does not work please , 
                    //post the solution in the comments.
                    if (!isFileNameFound) {
                        parsedDataObj.fileName = "NO_DATA";
                    }
                    parsedDataObj.packageName = "NO_DATA";
                    parsedDataObj.className = "NO_DATA";
                    parsedDataObj.functionName = "NO_DATA";
                }
            }
        }
    }
    return parsedDataObj;
}

Comments (5)add comment

nicholas said:

Building you're own debug tools? Save your self some work and look at http://www.actionscript-flash-...-for-flash Users who come across this post are often looking to create their own debug tools in the interest of saving them time they should check out Fireflash at the link provided. It is a tool that does advanced tracing in the flash/flex IDE console and also feeds debugging information out to the popular Firebug console which is awesome for debugging web applications that have interdependencies between Javascript and ActionScript 3.0 (AS3). Fireflash is unique in the fact that it allows you to browse public properties of a traced object and in turn you can open each property and view all of their properties. Peace.
 
report abuse
vote down
vote up
January 01, 2010 | url
Votes: +1

Nicholas said:

Code has been updated to not fail in the debugger.
 
report abuse
vote down
vote up
January 05, 2010 | url
Votes: +0

sharedtut said:

thank you
 
report abuse
vote down
vote up
January 21, 2010 | url
Votes: +0

bas said:

I use this class in flash builder. and things work most of the time. Thanks

However, when a class is the root/default package, no data is found. Also I wish I would get the line number too.

Error: ah an error
at test::Main()[/Users/... .../src/test/Main.as:20]

vs

Error: ah an error
at Main()[/Users/... .../src/test/Main.as:20]

does not work
 
report abuse
vote down
vote up
April 07, 2010
Votes: +0

Jay said:

Really appreciate your parsing solution; we built a utility class around it that helps give context to where trace statements are coming from when developing and debugging. Check it out. Thanks!

Here's the URL to the utility class that makes use of this: http://blog.unionstudio.net/20...uggernaut/
 
report abuse
vote down
vote up
April 26, 2010 | url
Votes: +0

Write comment
quote
bold
italicize
underline
strike
url
image
quote
quote
smile
wink
laugh
grin
angry
sad
shocked
cool
tongue
kiss
cry
smaller | bigger

security image
Write the displayed characters


busy