扩展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也是一样的,不帖了)