View Single Post
suki_babee suki_babee is offline 2008-08-06 #5 Old  
Yes you can..
Last edited by suki_babee : 2008-08-21 at 09:21.
UPDATED: all you need to do is:

var e:Error = new Error();
var s:String = e.getStackTrace();
trace(s);

this only works with the debug flash player (s=null otherwise). It gives you a stack trace with line numbers (line numbers only if you have "Permit Debugging" enabled when your SWF is published). I wrote a class to do this elegantly and I added a bunch more features. 3 ways to use it:

Trace.log(5, "this is a trace point"); // basic trace point
Trace.codetrace(5, "how did this get called"); // more interesting called within a stack
Trace.print_r(5, "this is my obj", obj); // traces out contents of obj or array (only public elements if instance)

And you can turn the trace off when you want better performance for a published swf:

Trace.set_trace_type(Trace.TYPE_NONE);


Sample output. I prefix with "fa!" ('fa' for FlickAway.com - but you can change that) followed by level (1 char), followed by timestamp (min:sec:milli) [caller] <msg>. The prefix is so I can filter out other swf tracing from mine when testing in Firefox + FlashTrace:
Code:
fa!5 49:19:375 [Image/load():38] this is a trace point
fa!5 49:19:375 [Image/load():43] how did this get called?
fa!5            +--[Image():28]
fa!5            +--[HomePageImage():23]
fa!5            +--[HomeDefault():67]
fa!5 21:59:750 [FileInfo():39] this is my obj (print_r) com.flickaway::FileInfo => 
fa!5            [fver]:int => 0
fa!5            [caption]:String => ""
fa!5            [fidp]:String => "0/0/7/a1_373lrkz9z"

com/flickaway/Trace.as:
Code:
/**
* This provides full, quick and no tracing capabilities (as much as ActionScript allows) via the exception
* mechanism, which I imagine could impede performance.  It provides caller information.
*
* Use: set_trace_type with TYPE_NONE, TYPE_QUICK and TYPE_FULL + TYPE_REMOTE (new - to test with non-debug flash player)
*
* @author    Glen
* @copyright 2006 flickaway.com
* @version   $Id: Trace.as 1710 2008-08-21 16:51:03Z glen $
*/

package com.flickaway
{
  import flash.events.StatusEvent;
  import flash.net.LocalConnection;
  import flash.utils.describeType;

  public class Trace
  {
    static public const TYPE_NONE   :uint  = 0;                      // To turn off tracing (for production) and save cycles
    static public const TYPE_QUICK  :uint  = 1;                      // To avoid generating and parsing stacktrace + using trace() for output
    static public const TYPE_FULL   :uint  = 2;                      // The norm - Full tracing + using trace() for output
    static public const TYPE_REMOTE :uint  = 3;                      // Full tracing, but sending it to another swf via LocalConnection

    static private var my_type:uint = TYPE_FULL;                     // defaults to FULL
    static private var conn:LocalConnection;
    static private var lc_name:String = '_flickaway_trace';          // Local connection name
    static private var lc_func:String = 'log';                       // Local connection function

    static public function set_trace_type(type:uint):void
    {
      Trace.my_type = type;
      if (type == Trace.TYPE_REMOTE)
      {
        Trace.conn = new LocalConnection();
        Trace.conn.addEventListener(StatusEvent.STATUS, Trace.on_status_handler);
      }
    }

    static public function on_status_handler(event:StatusEvent):void
    {
      switch (event.level)
      {
        case "status" : break;             // succeeded
        case "error"  : trace("FA Trace: LocalConnection to " + Trace.lc_name + ":" + Trace.lc_func + " failed.");  break;
      }
    }

    static public function log(level:uint, msg:String):void
    {
      switch (Trace.my_type)
      {
        case TYPE_NONE:   return;
        case TYPE_FULL:                                               // conditional logic inside
        case TYPE_REMOTE: Trace.log_full(level, msg); break;          // dito
        case TYPE_QUICK:  Trace.log_quick(level, msg); break;

        default:
          throw new Error("Cannot handle trace type of " + Trace.my_type);
      }
    }

    static public function error(level:uint, msg:String):void
    {
      switch (Trace.my_type)
      {
        case TYPE_NONE:   Trace.log_full(level, msg); break;                                 // on production systems, we want to see these still
        case TYPE_FULL:                                                                      // conditional logic inside
        case TYPE_REMOTE: Trace.log_full(level, msg); throw new Error(msg); break;           // Log AND throw an exception
        case TYPE_QUICK:  Trace.log_full(level, msg); throw new Error(msg); break;           // Log AND throw an exception
        default:
          throw new Error("Cannot handle trace type of " + Trace.my_type);
      }
    }

    static public function codetrace(level:uint, msg:String):void
    {
      switch (Trace.my_type)
      {
        case TYPE_NONE:   return;
        case TYPE_FULL:                                                       // conditional logic inside
        case TYPE_REMOTE: Trace.codetrace_full(level, msg); break;            // dito
        case TYPE_QUICK:  Trace.log_quick(level, msg); break;                 // in quick mode - we cannot do the codetrace
        default:
          throw new Error("Cannot handle trace type of " + Trace.my_type);
      }
    }

    static public function print_r(level:uint, msg:String, obj:*):void
    {
      switch (Trace.my_type)
      {
        case TYPE_NONE:   return;
        case TYPE_FULL:                                                      // conditional logic inside
        case TYPE_REMOTE: Trace.print_r_full(level, msg, obj); break;        // dito
        case TYPE_QUICK:  Trace.print_r_quick(level, msg, obj); break;
        default:
          throw new Error("Cannot handle trace type of " + Trace.my_type);
      }
    }


    //==================================================================================================================================
    //
    // QUICK TRACE
    //
    //==================================================================================================================================

    static private function log_quick(level:uint, line:String):void
    {
      var d:Date = new Date();
      var m = d.getMinutes();
      var s = d.getSeconds();
      var ms = d.getMilliseconds();
      Trace.write("fa!" + level + "-" + (m>=10?m:'0'+m) + ":" + (s>=10?s:'0'+s) + ":" + (ms>=100?ms:(ms>=10?'0'+ms:'00'+ms)) + " " + line);
    }

    static private function print_r_quick(level:uint, msg:String, obj:*):void
    {
      Trace.log(level, msg + " (print_r of <?something?>)");
    }



    //==================================================================================================================================
    //
    // FULL TRACE
    //
    //==================================================================================================================================

    static private function log_full(level:uint, msg:String, snum:uint=3):void
    {
      // FROM:
      // http://snippets.dzone.com/posts/show/3703
      //----------------------------------------------------------------------------------------------------------------
      // With debugging turned on, this is what we get:
      //
      // Error
      // <tab>at com.flickaway::Trace$/log_full()[D:\web\flickaway_branch\flash\lib\com\flickaway\Trace.as:83]
      // <tab>at com.flickaway::Trace$/print_r_full()[D:\web\flickaway_branch\flash\lib\com\flickaway\Trace.as:114]
      // <tab>at com.flickaway::Trace$/print_r()[D:\web\flickaway_branch\flash\lib\com\flickaway\Trace.as:46]
      // <tab>at com.flickaway::Params()[D:\web\flickaway_branch\flash\lib\com\flickaway\Params.as:36]                <==== this line we want
      // <tab>at com.flickaway::Params$/get_instance()[D:\web\flickaway_branch\flash\lib\com\flickaway\Params.as:27]
      // <tab>at HomeDefault()[D:\web\flickaway_branch\flash\homepage\HomeDefault.as:57]
      // <tab>at com.flickaway::Params()[D:\web\flickaway_branch\flash\lib\com\flickaway\Params.as:36])
      //
      // with debugging turned off:
      //
      // Error
      // <tab>at com.flickaway::Trace$/log_full()
      // <tab>at com.flickaway::Trace$/print_r_full()
      // <tab>at com.flickaway::Trace$/print_r()
      // <tab>at com.flickaway::Params()
      // <tab>at com.flickaway::Params$/get_instance()
      // <tab>at HomeDefault()
      //----------------------------------------------------------------------------------------------------------------
      var e = new Error();
      var str:String = e.getStackTrace();                     // get the full text str
      //Trace.write("str.length=" + str);
      if (str == null)                                          // means we aren't on the Debug player
      {
        Trace.log_it(level, "(!debug) " + msg);
      }
      else
      {
        var stacks:Array = str.split("\n");                     // split into each line
        var caller:String = Trace.gimme_caller(stacks[snum]);   // get the caller for just one specific line in the stack trace
        Trace.log_it(level, caller + " " + msg);
      }
    }


    static private function codetrace_full(level:uint, msg:String, snum:uint=3):void
    {
      var e:Error = new Error();
      //----------------------------------------------------------------------------------------------------------------
      // This is just like log_full() - except we print out all lines in the stack, starting at snum
      //----------------------------------------------------------------------------------------------------------------
      var str:String = e.getStackTrace();                     // get the full text str

      if (str == null)                                        // means we aren't on the Debug player
      {
        Trace.log_it(level, "no_debug " + msg);
      }
      else
      {
        var stacks:Array = str.split("\n");                     // split into each line
        var caller:String = Trace.gimme_caller(stacks[snum]);   // get the caller info for just one specific line in the stack trace
        Trace.log_it(level, caller + " " + msg);

        if (snum < stacks.length)                           // this means there's more in the stack to print out
        {
          for (var i = snum+1; i < stacks.length; i++)
          {
            caller = Trace.gimme_caller(stacks[i]);
            Trace.write("fa!" + level + "            +--" + caller);
          }
        }
      }
    }


    /**
     * Returns a string like "[HomeDefault():51]" - line number present only if "permit debugging" is turned on.
     */
    static private function gimme_caller(line:String):String
    {
      //-------------------------------------------------------------------------------------------------
      // the line can look like any of these (so we must be able to clean up all of them):
      //
      // <tab>at com.flickaway::Params()
      // <tab>at com.flickaway::Params()[D:\web\flickaway_branch\flash\lib\com\flickaway\Params.as:36]
      // <tab>at HomeDefault()
      // <tab>at HomeDefault()[D:\web\flickaway_branch\flash\homepage\HomeDefault.as:57]
      //-------------------------------------------------------------------------------------------------
      var dom_pos:int = line.indexOf("::");                  // find the '::' part
      var caller:String;

      if (dom_pos == -1)
      {
        caller = line.substr(4);                         // just remove '<tab>at ' beginning part (4 characters)
      }
      else
      {
        caller = line.substr(dom_pos+2);                 // remove '<tab>at com.flickaway::' beginning part
      }
      var lb_pos:int = caller.indexOf("[");                // get position of the left bracket (lb)

      if (lb_pos == -1)                                    // if the lb doesn't exist (then we don't have "permit debugging" turned on)
      {
        return "[" + caller + "]";
      }
      else
      {
        var line_num:String = caller.substr(caller.lastIndexOf(":"));      // find the line number
        caller = caller.substr(0, lb_pos);                                 // cut it out - it'll look like ":51]"
        return "[" + caller + line_num;                                    // line_num already has the trailing right bracket
      }
    }



    static private function print_r_full(level:uint, msg:String, obj:*):void
    {
      Trace.log_full(level, msg + " (print_r) " + Trace.pr(level, obj), 4);
    }


    // FROM:
    // http://blogs.grf-design.com/archives/2007/07/actionscript_3.html
    static private function pr(level:uint, o:*, name:String = "", recur:int = 0):String
    {
      var result:String = "";
      var type:String   = typeof(o);
      var desc:XML      = describeType(o);

      if (type == "function")
      {
        return result;
      }

      // meta data of object
      if (recur != 0)
      {
        result += "\nfa!" + level + "          ";
        for (var i:int = 0; i < recur; ++i)
        {
          result += "  ";
        }
      }

      if (name)
      {
        result += '[' + name + ']:';
      }
      result += desc.@name + ' => ';

      // content of object
      switch (type)
      {
        case "boolean":
        case "number":
          result += String(o);
          break;

        case "string":
          result += '"' + String(o) + '"';
          break;

        case "xml":
          result += o.toXMLString();
          break; 0

        case "object":
          if (desc.@name == "Object" || desc.@name == "Array")
          {
            for (var key:String in o)
            {
              //result += "\n";
              result += pr(level, o[key], key, (recur + 1));
            }
          }
          else
          {
            var prop:XML;
            // -- properties
            for each (prop in desc.variable)
            {
              result += pr(level, o[prop.@name], prop.@name, (recur + 1));
            }
            // -- methods
            for each (prop in desc.method)
            {
              result += pr(level, o[prop.@name], prop.@name, (recur + 1));
            }
          }
          break;

        case "function":                                  // I dont want to print out functions
          result += String(o);
          break;

          default:
            Trace.write("ERROR: not handling type: " + type);
      }

      return result;
    }


    static private function log_it(level:uint, line:String):void
    {
      var d:Date = new Date();
      var m = d.getMinutes();
      var s = d.getSeconds();
      var ms = d.getMilliseconds();

      Trace.write("fa!" + level + " " + (m>=10?m:'0' + m) + ":" + (s>=10?s:'0' + s) + ":" + (ms>=100?ms:(ms>=10?'0' + ms:'00' + ms)) + " " + line);
    }


    static private function write(str:String):void
    {
      if (Trace.my_type == Trace.TYPE_REMOTE)
      {
        Trace.conn.send(Trace.lc_name, Trace.lc_func, str);
      }
      else
      {
        trace(str);
      }
    }

  }
}
Reply With Quote