在AS3中创建自定义trace()类

时间:2009-04-03 21:12:05

标签: actionscript-3 debugging logging

我有了扩展trace()消息的想法。

为什么

trace()遍及我的代码,我想通过一个简单的命令打开/关闭它们,并且可能为trace()添加某种优先级功能,即

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

当我跑步时,只有优先级较高的一个,在这种情况下为“1”。

我还想添加更多功能,例如将消息记录到文件等等。

问题

trace()如何工作? - 有可能以某种方式超载trace()吗? - 我如何实现自定义TraceMsg(这里有什么代码?)方法?

在我们最喜欢的搜索引擎上找到有关此主题的信息存在严重问题,因此我们将不胜感激。

9 个答案:

答案 0 :(得分:5)

我已经提出了一种在Flash专用项目中使用我自己的trace()函数的一种相当高效但又乏味的方法,但只需用

调用它
trace("this", "that", "and that too");

我基本上在我的项目的每个类中实现一个trace()方法,它调用一个公共函数(这样我就可以从那里调用真正的trace()函数。

这就是我所做的:在每个课程中我称之为

include "trace_implementation.as";
.as文件中的

是一个简单的方法实现(也可能是静态方法)。

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

并且myTrace函数在其自己的myTrace.as文件中定义

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*/
    }
}

所以现在当我使用“省略跟踪操作”进行编译时,我的整个调试将被忽略,就好像我只是使用了trace()一样。

这里非常好的部分是你可以根据你在跟踪中给出的指示实现自定义操作,所以:

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

然后从myTrace或Tracer类或其他任何东西发送它:)

希望这有助于未来的追踪者。

答案 1 :(得分:3)

trace()本身是一个顶级函数,而不是一个类,所以不幸的是我们无法扩展它。话虽这么说,我们可以在一个简单的类中使用它来完成正常的操作,只有在这种情况下,跟踪基于条件(即Boolean - true | false等)。首先我们创建Trace类,我们不会自己实例化,因为我们通过下面的类,Tracer使用Factory设计模式。 Tracer是围绕单例设计模式构建的,但在调用Tracer的跟踪方法时,利用Factory模式实例化Trace的实例。

//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
        }
    }
}

请记住,这是不合适的,很可能会有一两个错误,但这个想法就在那里;也就是说,这没有经过测试,只是为了让您了解如何实现这一点。

我希望这会有所帮助。

答案 2 :(得分:2)

查看Flex logging API,尤其是以下部分:使用日志记录API实现自定义记录器

同时查找TraceTarget课程。

答案 3 :(得分:2)

你不能覆盖trace本身,但为了便于输入,我想创建一个名为'tr'的全局函数。一个鲜为人知的事实是你可以在AS3中创建全局函数,但这很简单。

在主源目录(不在子目录或包中)内创建名为tr.as的文件,内容为:

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

如果你需要有很多逻辑或静态存储变量等,那么建立一个单独的静态类可能会更好,并让全局tr函数调用它,例如:

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

答案 4 :(得分:1)

这是我使用的超级简单的自定义跟踪功能。 debugFlag可以设置为true / false 包裹中的其他地方。

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

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

}

答案 5 :(得分:1)

在AS2中,可以通过执行类似这样的操作来覆盖全局跟踪功能(从内存中获取,可能有点不对,但它的要点就在那里):

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);
}

不幸的是,我还没有找到在AS3中做同样事情的方法。爱好。

答案 6 :(得分:1)

Trace是一个顶级函数,所以你不能覆盖它,据我所知,它不会触发任何事件。由于它是顶级函数(未包含在任何命名包中),因此可以在没有import语句的情况下使用它。

以下是一个顶级“Tracer”类的示例,您可以使用它来代替没有import语句的跟踪。

只需调用“Tracer.write”或“Tracer.writeError”即可跟踪Error对象。 “Tracer.write”接受可变数量的参数,就像内置跟踪函数一样。 “Tracer.writeError”是一种帮助方法,可以让您轻松跟踪Error对象。

功能

  1. 调用内置跟踪。
  2. 将您对Tracer.write的所有调用记录为一个字符串数组。
  3. 可以通过getText以字符串形式访问调用日志,该字符串使用换行符连接数组中的所有元素,并且可选择添加行号!
  4. 在将新行添加到日志时触发事件,因此如果您有某种日志显示窗口,则显示窗口可以侦听Tracer事件,以便在事件发生时实时更新日志显示。这非常适合在Web浏览器或独立播放器中运行时显示跟踪事件。
  5. -Tracer类定义

    package
    {
        import flash.events.EventDispatcher;
    
        public class Tracer extends EventDispatcher
        {
            private static var traced_text:Array = new Array( "--Start of Trace Log--" );
            public static var enabled:Boolean = true;
            private static var suspended:Boolean = false;
            public static var instance:Tracer = new Tracer();
            public static const newline:String = "\n"; //workaround for TextField.appendText bug.. use "\n" instead of "\r".  See note and link to bug post in getText method
    
            public function Tracer()
            {
            }
    
            static public function write( ...args ):void
            {
                if (enabled && !suspended)
                {
                    trace.apply( null, args );
                    var text:String = args.join( newline );
                    var next_index:int = traced_text.length;
                    traced_text.push( text );
                    suspended = true; //prevent recursive calls from TracerEvent handler
                    instance.dispatchEvent( new TracerEvent( text, next_index ) );
                    suspended = false;
                }
            }
    
            static public function writeError( e:Error ):void
            {
                write( "errorID: " + e.errorID, "errorName: " + e.name, "errorMessage: " + e.message, "stackTrace: " + e.getStackTrace() );
            }
    
            static public function getText( include_line_numbers:Boolean ):String
            {
                var line_count:int = traced_text.length;
                var lines:Array = traced_text; //store pointer to traced_text; pointer may be changed to reference an altered array that includes line numbers
                if (include_line_numbers) //create temporary trace log copy with altered lines; allows quick call to join at end
                {
                    var new_lines:Array = new Array();
                    for (var i:int = 0; i < line_count; i++)
                        new_lines.push( i.toString() + ": " + lines[i] );
                    lines = new_lines;
                }
                return lines.join( newline ); //do not include last newline character (workaround for bug in appendText method (https://bugs.adobe.com/jira/browse/FP-1982); I have to call appendText with newline character first, otherwise it has issues like not acknoledging the newline thats already there at the end).
            }
    
            static public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void 
            {
                 instance.addEventListener(type, listener, useCapture, priority, useWeakReference);
            }
    
            static public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void 
            {
                instance.removeEventListener(type, listener, useCapture);
            }
    
            static public function willTrigger(type:String):Boolean 
            {
                return instance.willTrigger(type);
            }
    
            static public function hasEventListener(type:String):Boolean 
            {
                return instance.hasEventListener(type);
            }
        }
    }
    

    -TracerEvent类定义

    package
    {
        import flash.events.Event;
    
        public class TracerEvent extends Event
        {
            public static const WRITE:String = "te_write";
    
            public var text:String;
            public var index:int; //index of newly traced text in the traced_text array (trace log)
    
            public function TracerEvent( text:String, index:int ) 
            {
                super( WRITE, false, false );
                this.text = text;
                this.index = index;
            }
    
            override public function clone():Event 
            {
                return new TracerEvent( text, index );
            }
        }
    }
    

答案 7 :(得分:1)

如下所述,没有办法覆盖跟踪(至少不希望跟踪到达输出流),但实际上很容易创建自己的通用可访问日志记录功能。另外,您甚至可以定义一个普遍可访问的布尔值来打开或关闭日志记录:

log.as (请注意,文件名必须反映该函数的名称)

package {
    function log(... arguments):void {

        trace("Custom logging FTW!");
        if (logEnabled)
            trace(arguments);
    }
}

logEnabled.as (请注意,文件名必须反映变量的名称)

package {
    var logEnabled:Boolean = true;
}

<强> Main.as

package {

    import flash.display.MovieClip;

    public class Main extends MovieClip {

        public function Main() {
            log("Testing");
            logEnabled = false;
            log("Testing2");
        }
    }
}

<强>响应

Custom logging FTW!
Testing
Custom logging FTW!

答案 8 :(得分:0)

你不需要覆盖它,只需在项目中创建一个函数并调用它跟踪,然后任何跟踪调用将指向this.trace;)

function trace(... arguments){  
    yourfunction(arguments);
}