views:

2320

answers:

6

I got this idea of expanding my trace() messages.

Why

trace() is all over my code, I want to turn them on/off by a simple command and maybe add some sort of priority functionality to the trace(), i.e.

myTrace.TraceMsg("loosehere",debugme, 0);
myTrace.TraceMsg("winhere",debugme, 1);

And when I run, only the one with the higher priority, "1" in this case, shows.

There is a lot more functionality I would like to add as well, like logging messages to file and so on.

Problem

How do trace() work? -Is it possible to overload trace() somehow? -How would I implement the custom TraceMsg(what code here?) method?

Having some serious problems finding info on this subject on our favourite search engine, so any help would be appreciated.

A: 

Look at the Flex logging API, particularly the section: Implementing a custom logger with the logging API.

Look up the TraceTarget class as well.

dirkgently
+1  A: 

trace() itself is a top-level function, not a class, so unfortunately we cannot extend it. That being said, we can utilize it in a simple class to do just what it does normally, only in this case the trace is based on conditions (i.e. Boolean - true|false, etc). First we create the Trace class, which we wouldn't instantiate ourselves because we are utilizing a Factory design pattern through the class below, Tracer. Tracer is built around the singleton design pattern, yet utilizes the Factory pattern to instantiate instances of Trace, when the trace method of Tracer is called.

//This class is handled by Tracer, which is right below it.
//You WILL NOT instantiate these, nor hold references.
package
{
    public class Trace
    {
        private function _value:*;
        private function _trace:Boolean;

        public function Trace(pValue:*, pTrace:Boolean):void
        {
          _value = pValue;
          _trace = pTrace;
        }
        public function get value():*
        {
           return _value;
        }
        public function get trace():Boolean
        {
           return _trace;
        }
    }
}
//This is the important class and the only one you will work with.
package
{
    /**
     *Utilizes Singleton and Factory design patterns.
     */
    public class Tracer
    {
        private var _traceArray:Array;
        private static var _instance:Tracer;

        public function Tracer(pvt:PrivateClass = null):void
        {
            if(pvt == null)
            {
                throw(new Error("You cannot instantiate this class directly, please use the static getInstance method."));
            }

            _init();
        }
        public static function getInstance():Tracer
        {
            if(Tracer._instance == null)
            {
                Tracer._instance = new Tracer(new PrivateClass());
            }
            return Tracer._instance;
        }
        public function trace(pValue:*, pTrace:Boolean):void
        {
           var trace:Trace = new Trace(pValue, pTrace);
           if(trace.pTrace)
           {
               trace(pValue);
           }
        }
        //Since we have the option for individual traces to be disabled
        //I provide this to get access to any and all later.
        public function traceAll():void
        {
            traceStr:String = _traceArray.toString();
        }
        public function get traceables():Array
        {
            return _traceArray;
        }
        //Here we provide a method to trace all, even if set to false in their constructor.
        private function _init():void
        {
            _traceArray = new Array();
        }
    }
}
//Here we create a class that is OUTSIDE of the package.
//It can only be accessed from within this class file.  We use this
//to make sure this class isn't instantiated directly.
class PrivateClass
{
    function PrivateClass():void
    {
        trace('can only be accessed from within this class file');
    }
}

//Now for use in doc class
package
{
    import flash.display.Sprite;
    import flash.events.Event;

    //No need to import Tracer and Trace, they are also in the
    //unnamed package.

    public class DocumentClass extends Sprite
    {
        private var _tracer:Tracer;

        public function DocumentClass():void
        {
            if(stage) _init();
            else addEventListener(Event.ADDED_TO_STAGE, _init);
        }
        private function _init(e:Event = null):void
        {
            _tracer = Tracer.getInstance();
            _tracer.trace(10*20, false);
            _tracer.trace(10*20, 0); //SAME AS ABOVE
            _tracer.trace("I love AS3", true); //traces
            _tracer.traceAll(); //Would trace: 200, 200, I love AS3
        }
    }
}

Keep in mind this is off the hip and very well could have a bug or two, but the idea is there; That is to say that this is not tested, it is merely to give you an idea of how you might implement this.

I hope this helps.

Brian Hodge
blog.hodgedev.com

Brian Hodge
Very nice ideas, will look into as soon as I find the time. Thanks!
Daniel T. Magnusson
+1  A: 

Here is a super simple custom trace function I use. debugFlag can be set to true/false elsewhere in the package.

public static function myTrace(... vars) :void {

if (debugFlag) {
 var output:Array = new Array;
 for each (var arg in vars) {
          output.push(arg);
    }
 trace(output);
}

}

+4  A: 

I have come up with a rather efficient, yet tedious way of using my own trace() function in Flash only projects, but calling it simply with

trace("this", "that", "and that too");

I basically implement one trace() method in every class of my project, that calls a public function (so that i can call the real trace() function from there.

here is what I do : in every class I call this

include "trace_implementation.as";

in the .as file comes a simple method implementation (it could be a static method too).

public function trace(... arguments){
    for(var i in arguments){
        myTrace(arguments[i]);
    }
}

and the myTrace function is defined in its own myTrace.as file

package pt.utils{
    import flash.external.ExternalInterface

    public function myTrace(_s:String):void{
        trace(_s);// this will call the original flash trace() function
        ExternalInterface.call("console.log", _s);// to get traces outside of flash IDE
            /*implement what you want here*/
    }
}

so now when I compile with "omit trace actions", my whole debugging is ignored as if I used trace() simply.

the really good part here is that you could implement custom actions depending on instructions you give in the trace, so :

trace(Debug.DEBUG_MESSAGE, "message to output in debug");
trace(Profile.START_PROFILING, this, 'name');
/*do heavy code*/
trace(Profile.STOP_PROFILING, this);

then dispatch it from myTrace, or a Tracer class or anything :)

Hope this helps future tracers.

Boris
Just what I needed! Thank you very much!
davgothic
+1  A: 

In AS2, it was possible to override the global trace function by doing something like this (taken from memory, might be a bit wrong but the gist of it is there):

public static var realTrace:Function = _global["trace"];

// This is put in some init code somewhere
_global["trace"] = myTrace;

public static function myTrace(... args):void
{
    // Do whatever you want with args here, build a nice formatted string or whatever
    // before passing to realTrace. Using with MTASC one could add line numbers, class
    // names and all sorts of nice meta data. Or just return should you want to turn
    // tracing off.
    realTrace.apply(args);
}

Unfortunately I haven't found a way to do the same in AS3. Yet.

macke
A: 

You can't override trace itself, but for ease of typing I like to create a global function called 'tr'. It's a little known fact that you can create global functions in AS3, but it's easy.

Create a file called tr.as inside you main source directory (not in a subdirectory or package), with the contents:

package {
  public function tr(msg:String, ...):void {
    // add custom trace logic here
    trace("tr message: "+msg);
  }
}

If you need to have a lot of logic or static storage variables etc, it might be better to make a separate static class, and have the global tr function call out to that, such as:

package {
  import org.code.MyTracer;
  public function tr(msg:String, ...):void {
    MyTracer.tr(msg); // all the tracing logic is inside the MyTracer class
  }
}
davr