JavaScript的Console擴展和輸出級別控制

擴展Console的原由

目前網上還沒有類似的教程哦。
Console作爲日誌輸出調試的功能還是很強大的。可以打印正常的日誌信息,錯誤信息(log,info,warn,error)等等,還可以詳細詳細顯示函數調用棧,信息的輸出函數名以及代碼位置,功能可謂非常強大。
這裏寫圖片描述
但是有個問題就是無法根據日誌的等級來自由控制輸出權限。比如我設置一個等級,只能輸出warn和error這樣。雖然有可能發佈的時候,會把Console基本有從代碼中去掉,但是調試的時候有時也需要調整等級了。比如想暫時把log給屏蔽掉,只輸出info或者warn以上信息。

最開始是想寫個Log日誌類來擴展Console的,增加控制日誌等級之類的功能。寫好之後,發現一個很鬱悶的問題,那就是自己的日誌輸出,遠遠沒有Console自帶的強大。因爲Console輸出信息的時候,可以把當前類和那一行代碼的信息給打印出來。這個很強大,對於調試非常有用,而自己寫的Log沒有這個功能。
用自己的Log進行擴展,則無法顯示出真實的代碼路徑,變成自己寫的Log路徑了。看下圖
這裏寫圖片描述
當然這個輸出日誌路徑是方便本地調試看。如果需要把日誌錯誤等信息收集發給服務器,自定義擴展Log還是可行的。
針對這樣的情況,我對Console對象進行了擴展。增加了相應的功能。

Console增加等級控制和擴展分析

演示代碼爲TypeScript的代碼。後面會給出完整的TypeScript和JavaScript的代碼。

1日誌輸出等級控制

首先是準備增加等級控制,比如我可以調整日誌的輸出級別,來決定trace,log,info,error等輸出。原理其實很簡單,利用原型重寫對應的方法。根據等級,把小於日誌輸出等級的方法設置爲一個空方法,什麼也不做,這樣就無法輸出信息了。
對輸出方法進行分級別

 /** 調試級別,trace函數路徑 **/
 static TRACE:number = 0;
  /** 普通日誌級別 **/
  static LOG:number = 1;
  /** 信息日誌級別 **/
  static INFO:number = 2;
  /** 警告日誌級別 **/
  static WARN:number = 3;
  /** 錯誤日誌級別 **/
  static ERROR:number = 4;
  /** 需要屏蔽覆蓋的方法名 **/
  private static funNames:string[] = ["trace","log","info","warn","error"];

實現過程是這樣的:
先把console原來的trace,log等function給存放起來,當進行等級控制時,先把所有的方法都設置爲空方法,然後把大於等於日誌級別的方法給恢復過來。

//設置回最初的方法
 for(var i:number = 0; i < this.funNames.length; i++)
 {
     //定義個空方法屏蔽掉
     console[this.funNames[i]] = this.emptyFun;
 }
 //根據this.$level來還原輸出方法
 for(var i:number = this.$level; i < this.funNames.length; i++)
 {
      //還原成最初的方法
      console[this.funNames[i]] = this.funList[i];
  }

原理就是這麼簡單,然後進行包裝的代碼就會稍微多一點。看輸出效果。

// //開啓擴展日誌
asf.ConsolePlus.init();
console.log("擴展日誌的正常模式");
console.log("log的信息");
console.info("info的信息");
console.warn("warn的信息");
// console.error("error的信息");
console.log("把日誌等級調整爲WANR");
//設置日誌等級,warn,就只有warn的信息才能輸出
asf.ConsolePlus.setLevel(asf.ConsolePlus.WARN);
console.log("log的信息");
console.info("info的信息");
console.warn("warn的信息");
console.error("error的信息");

輸出結果是這樣的
這裏寫圖片描述
可以看到把日誌等級調整爲WARN之後,就無法看到log和info的信息了。

強化Console的輸出方法

這個實現其實主要是後期擴展,需要把日誌傳給服務器或者其他調試端的時候才需要的。主要原理其實是在原有的log,info等方法的後面增加自己的信息(當然也可以發給服務器)。類似java的AOP面向切面編程。

/**
 * 創建擴展函數
 * @param oldFun 原有的函數
 * @param funName 函數名稱
 */
private static createPlusFun(oldFun:Function,funName:string):void
{
    var fun:Function = function (message?: any, ...optionalParams: any[]):void
    {
        console.group("[" + funName + "][" + new Date() + "]");
        oldFun.apply(console,arguments);
        console.groupEnd();
    }
    this.funPulsList.push(fun);
}
asf.ConsolePlus.openConsolePlus();
console.log("log的信息");
console.info("info的信息");
console.warn("warn的信息");

前後增加了個組顯示的簡單擴展,看具體的輸出效果。
這裏寫圖片描述

完整的TypeScritp和JavaScript代碼

TypeScritp代碼

/**
 * Created by sodaChen on 2017/3/1.
 */
namespace asf
{
    /**
     * 輸出信息擴展類
     * @author sodaChen
     * Date:2017/2/15
     */
    export class ConsolePlus
    {
        /////////////////日誌級別////////////////
        /** 調試級別,trace函數路徑 **/
        static TRACE:number = 0;
        /** 普通日誌級別 **/
        static LOG:number = 1;
        /** 信息日誌級別 **/
        static INFO:number = 2;
        /** 警告日誌級別 **/
        static WARN:number = 3;
        /** 錯誤日誌級別 **/
        static ERROR:number = 4;

        /** 默認是最初的日誌級別,改變這個值。可以改變日誌輸出的結果 **/
        private static $level:number = ConsolePlus.LOG;
        /** 是否開啓擴展模式 **/
        private static isPlusMode:boolean;
        /** 需要屏蔽覆蓋的方法名 **/
        private static funNames:string[] = ["trace","log","info","warn","error"];
        /** console最初的方法緩存 **/
        private static funList:Function[];
        /** 擴展後的方法級別 **/
        private static funPulsList:Function[];
        /** 空方法 **/
        private static emptyFun:Function;

        static init(isPlusMode:boolean = false):void
        {
            this.funList = [];
            this.funPulsList = [];
            this.emptyFun = function(){};

            //存放原來的方法
            for(var i:number = 0; i < this.funNames.length; i++)
            {
                this.funList.push(console[this.funNames[i]]);
            }
            //生成新的擴展方法
            for(var i:number = 0; i < this.funNames.length; i++)
            {
                this.createPlusFun(this.funList[i],this.funNames[i]);
            }
            this.setConsoleMode(isPlusMode);
        }

        /**
         * 設置日誌等級,所有大於等於這個日誌級別的輸出都可以正常輸出,小於的則不能進行輸出
         * @param level
         */
        static setLevel(level:number):void
        {
            this.$level = level;
            this.openConsole();
        }
        /**
         * 設置輸出模式
         * @param isPlusMode 是否爲擴展模式
         */
        static setConsoleMode(isPlusMode:boolean):void
        {
            this.isPlusMode = isPlusMode;
            if(isPlusMode)
                this.openConsolePlus();
            else
                this.openConsole();
        }

        /**
         * 打開日誌
         */
        static openConsole():void
        {
            this.closeConsole();
            //擴展默認,則調用擴展方法
            if(this.isPlusMode)
            {
                this.openConsolePlus();
                return ;
            }
            for(var i:number = this.$level; i < this.funNames.length; i++)
            {
                //還原成最初的方法
                console[this.funNames[i]] = this.funList[i];
            }
        }

        /**
         * 關閉所有的日誌輸出
         */
        static closeConsole():void
        {
            //設置回最初的方法
            for(var i:number = 0; i < this.funNames.length; i++)
            {
                //定義個空方法屏蔽掉
                console[this.funNames[i]] = this.emptyFun;
            }
        }

        /**
         * 開啓日誌輸出的擴展模式
         */
        static openConsolePlus():void
        {
            this.isPlusMode = true;
            //擴展console的所有方法
            for(var i:number = this.$level; i < this.funNames.length; i++)
            {
                console[this.funNames[i]] = this.funPulsList[i];
            }
        }
        /**
         * 關閉日誌輸出的擴展模式
         */
        static closeConsolePlus():void
        {
            this.isPlusMode = false;
            //還原成原來的方法
            this.openConsole();
        }
        /**
         * 創建擴展函數
         * @param oldFun 原有的函數
         * @param funName 函數名稱
         */
        private static createPlusFun(oldFun:Function,funName:string):void
        {
            var fun:Function = function (message?: any, ...optionalParams: any[]):void
            {
                console.group("[" + funName + "][" + new Date() + "]");
                oldFun.apply(console,arguments);
                console.groupEnd();
            }
            this.funPulsList.push(fun);
        }
    }
}

完整的調試信息代碼:

// //開啓擴展日誌
asf.ConsolePlus.init();
console.log("擴展日誌的正常模式");
console.log("log的信息");
console.info("info的信息");
console.warn("warn的信息");
// console.error("error的信息");
console.log("把日誌等級調整爲WANR");
//設置日誌等級,warn,就只有warn的信息才能輸出
asf.ConsolePlus.setLevel(asf.ConsolePlus.WARN);
console.log("log的信息");
console.info("info的信息");
console.warn("warn的信息");
console.error("error的信息");
//設置回正常的log級別
asf.ConsolePlus.setLevel(asf.ConsolePlus.LOG);
console.log("啓動Console的擴展模式");
asf.ConsolePlus.openConsolePlus();
console.log("log的信息");
console.info("info的信息");
console.warn("warn的信息");
console.error("error的信息");
//輸出擴展模式也支持日誌等級的
console.log("Console的擴展模式調整日誌級別到warn");
asf.ConsolePlus.setLevel(asf.ConsolePlus.WARN);
console.log("log的信息");
console.info("info的信息");
console.warn("warn的信息");
console.error("error的信息");

asf.ConsolePlus.closeConsolePlus();
console.log("1關閉Console的擴展模式,正常輸出啦");
//得調級別才能輸出log
asf.ConsolePlus.setLevel(asf.ConsolePlus.LOG);
console.log("2關閉Console的擴展模式,正常輸出啦");

JavaScript代碼

注意,這個js代碼是TypeScript生成的代碼,所以有部分會很奇怪。具體我沒單獨調試運行過,請注意。

var asf;
(function (asf) {
    /**
     * 輸出信息擴展類
     * @author sodaChen
     * Date:2017/2/15
     */
    var ConsolePlus = (function () {
        function ConsolePlus() {
        }
        ConsolePlus.init = function (isPlusMode) {
            if (isPlusMode === void 0) { isPlusMode = false; }
            this.funList = [];
            this.funPulsList = [];
            this.emptyFun = function () { };
            //存放原來的方法
            for (var i = 0; i < this.funNames.length; i++) {
                this.funList.push(console[this.funNames[i]]);
            }
            //生成新的擴展方法
            for (var i = 0; i < this.funNames.length; i++) {
                this.createPlusFun(this.funList[i], this.funNames[i]);
            }
            this.setConsoleMode(isPlusMode);
        };
        /**
         * 設置日誌等級,所有大於等於這個日誌級別的輸出都可以正常輸出,小於的則不能進行輸出
         * @param level
         */
        ConsolePlus.setLevel = function (level) {
            this.$level = level;
            this.openConsole();
        };
        /**
         * 設置輸出模式
         * @param isPlusMode 是否爲擴展模式
         */
        ConsolePlus.setConsoleMode = function (isPlusMode) {
            this.isPlusMode = isPlusMode;
            if (isPlusMode)
                this.openConsolePlus();
            else
                this.openConsole();
        };
        /**
         * 打開日誌
         */
        ConsolePlus.openConsole = function () {
            this.closeConsole();
            //擴展默認,則調用擴展方法
            if (this.isPlusMode) {
                this.openConsolePlus();
                return;
            }
            for (var i = this.$level; i < this.funNames.length; i++) {
                //還原成最初的方法
                console[this.funNames[i]] = this.funList[i];
            }
        };
        /**
         * 關閉所有的日誌輸出
         */
        ConsolePlus.closeConsole = function () {
            //設置回最初的方法
            for (var i = 0; i < this.funNames.length; i++) {
                //定義個空方法屏蔽掉
                console[this.funNames[i]] = this.emptyFun;
            }
        };
        /**
         * 開啓日誌輸出的擴展模式
         */
        ConsolePlus.openConsolePlus = function () {
            this.isPlusMode = true;
            //擴展console的所有方法
            for (var i = this.$level; i < this.funNames.length; i++) {
                console[this.funNames[i]] = this.funPulsList[i];
            }
        };
        /**
         * 關閉日誌輸出的擴展模式
         */
        ConsolePlus.closeConsolePlus = function () {
            this.isPlusMode = false;
            //還原成原來的方法
            this.openConsole();
        };
        /**
         * 創建擴展函數
         * @param oldFun 原有的函數
         * @param funName 函數名稱
         */
        ConsolePlus.createPlusFun = function (oldFun, funName) {
            var fun = function (message) {
                var optionalParams = [];
                for (var _i = 1; _i < arguments.length; _i++) {
                    optionalParams[_i - 1] = arguments[_i];
                }
                console.group("[" + funName + "][" + new Date() + "]");
                oldFun.apply(console, arguments);
                console.groupEnd();
            };
            this.funPulsList.push(fun);
        };
        /////////////////日誌級別////////////////
        /** 調試級別,trace函數路徑 **/
        ConsolePlus.TRACE = 0;
        /** 普通日誌級別 **/
        ConsolePlus.LOG = 1;
        /** 信息日誌級別 **/
        ConsolePlus.INFO = 2;
        /** 警告日誌級別 **/
        ConsolePlus.WARN = 3;
        /** 錯誤日誌級別 **/
        ConsolePlus.ERROR = 4;
        /** 默認是最初的日誌級別,改變這個值。可以改變日誌輸出的結果 **/
        ConsolePlus.$level = ConsolePlus.LOG;
        /** 需要屏蔽覆蓋的方法名 **/
        ConsolePlus.funNames = ["trace", "log", "info", "warn", "error"];
        return ConsolePlus;
    }());
    asf.ConsolePlus = ConsolePlus;
})(asf || (asf = {}));

完整的調試代碼可以直接用上面那個ts的調試代碼,使用過程是完全一樣。(ts生成出來的那部分js也是一樣的,不帖了)

發佈了91 篇原創文章 · 獲贊 72 · 訪問量 78萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章