console 方法

(function(window) {
    var LOG_LEVELS = ["DEBUG", "LOG", "INFO", "WARN", "ERROR"], //日誌級別
        //TODO 是否可以做成隊列閾值和倒計時時間由UI配置?
        THRESHOLD = 200, // 觸發日誌上傳的閾值,設置大一點,避免高頻的請求導致併發問題
        TIMER = 1000, // 倒計時,間隔發送時間
        URL = location.protocol + "//__rosin__.qq.com",
        KEY = +new Date() + '_' + parseInt(Math.random() * 1e8); // 每個頁面生成一個唯一key

    // https的請求,使用另外的通信協議
    if(location.protocol === "https:") {
        URL = "https://" + location.host + '/?__rosin__';
    }

    /**
     * 上傳任務隊列
     * 隊列長度達到閾值觸發POST日誌
     * @type {{_queueArr: Array, add: add, _post: _post}}
     */
    var queue = {
        _queueArr: [], //數組模擬隊列
        add: function() {
            Array.prototype.push.apply(this._queueArr, arguments);
            clock.start();

            //隊列達到閾值就觸發上傳
            if (this._queueArr.length >= THRESHOLD) {
                this._post(this._queueArr.splice(0, this._queueArr.length));
                return;
            }
        },
        _post: function(logArr) {
            var headers = {};
            var setHeader = function(name, value) {
                headers[name.toLowerCase()] = [name, value]
            };
            var xhr = new XMLHttpRequest();
            var nativeSetHeader = xhr.setRequestHeader;

            setHeader('Accept', '*/*');

            setHeader('Content-Type', 'application/x-www-form-urlencoded');

            xhr.setRequestHeader = setHeader;
            xhr.onreadystatechange = function(){}; // do nothing
            xhr.open('POST', URL, true);
            // chrome 控制檯會看到一個報錯
            // A wildcard '*' cannot be used in the 'Access-Control-Allow-Origin' header when the credentials flag is true.
            // xhr.withCredentials = true;

            for (name in headers) nativeSetHeader.apply(xhr, headers[name]);
            
            xhr.send(JSON.stringify(logArr));
        }
    },

    /**
     * 自定義日誌對象
     * @type {{DELIMITER: string, _record: _record, debug: debug, log: log, info: info, warn: warn, error: error}}
     */
    FConsole = {
        DELIMITER: " ", //分隔符
        JSON_TAG_LEFT: '\uFFFE', // 用於標識json對象字符串的等寬字符
        JSON_TAG_RIGHT: '\uFEFF',
        _record: function(logLevel) {
            var log = {
                "key": KEY,
                "level": logLevel, //日誌級別
                "time": new Date().getTime() //日誌時間,時間戳
                // "url"  : window.location.href //記錄日誌的URL
            },
            content = ""; //日誌內容

            for (var i = 1; i < arguments.length; i++) {
                if (Array.isArray(arguments[i])) {
                    content += (i === 1 ? "" : FConsole.DELIMITER) + FConsole.JSON_TAG_LEFT + "[" + arguments[i] + "]" + FConsole.JSON_TAG_RIGHT;
                } else if (typeof arguments[i] === "object") {
                    content += (i === 1 ? "" : FConsole.DELIMITER) + FConsole.JSON_TAG_LEFT + JSON.stringify(arguments[i]) + FConsole.JSON_TAG_RIGHT;
                } else {
                    content += (i === 1 ? "" : FConsole.DELIMITER) + arguments[i];
                }
            }
            log["content"] = content;

            //日誌記錄加入隊列
            queue.add(log)
        },
        debug: function() {
            Array.prototype.unshift.call(arguments, LOG_LEVELS[0]);
            FConsole._record.apply(FConsole, arguments);
        },
        log: function() {
            Array.prototype.unshift.call(arguments, LOG_LEVELS[1]);
            FConsole._record.apply(FConsole, arguments);
        },
        info: function() {
            Array.prototype.unshift.call(arguments, LOG_LEVELS[2]);
            FConsole._record.apply(FConsole, arguments);
        },
        warn: function() {
            Array.prototype.unshift.call(arguments, LOG_LEVELS[3]);
            FConsole._record.apply(FConsole, arguments);
        },
        error: function() {
            Array.prototype.unshift.call(arguments, LOG_LEVELS[4]);
            FConsole._record.apply(FConsole, arguments);
        }
    },

    /**
     * 全局定時器,監聽隊列
     * @type {{timeout: null, start: Function, clear: Function}}
     */
    clock = {
        timeout: null,
        start: function() {
            var self = this;
            if (!this.timeout) this.timeout = setInterval(function() {
                if (queue._queueArr.length > 0) {
                    queue._post(queue._queueArr.splice(0, queue._queueArr.length));
                }
            }, TIMER);
        },
        clear: function() {
            clearTimeout(this.timeout);
            this.timeout = null;
        }
    };


    function _extendObj(obj) {
        if (typeof obj !== 'object') return obj;
        var source, prop;
        for (var i = 1, length = arguments.length; i < length; i++) {
            source = arguments[i];
            for (prop in source) {
                if (Object.prototype.hasOwnProperty.call(source, prop)) {
                    // 不覆蓋原方法執行,只是加個殼
                    (function(obj, prop) {
                        if (typeof obj[prop] === "function") {
                            var oldFun = obj[prop].bind(obj);
                            obj[prop] = function() {
                                source[prop].apply(source, arguments);
                                // oldFun.apply(obj, arguments);
                                oldFun(arguments[0]);
                            };
                        } else {
                            obj[prop] = source[prop];
                        }
                    })(obj, prop);
                }
            }
        }
        return obj;
    };
    //將自定義的日誌API覆蓋到原生console中
   // _extendObj(window.console, FConsole);

})(window);

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章