angular代码设计之异常日志设计

angular代码分析之异常日志设计

错误异常是面向对象开发中的记录提示程序执行问题的一种重要机制,在程序执行发生问题的条件下,异常会在中断程序执行,同时会沿着代码的执行路径一步一步的向上抛出异常,最终会由顶层抛出异常信息。而与异常同时出现的往往是日志,而日志往往需要记录具体发生异常的模块、编码、详细的错误信息、执行堆栈等,方便问题的快速定位分析。angularjs作为前端的框架,其对异常信息的处理是怎样的呢?

一、定义模块和异常类型

首先每个模块的日志模块编码是一样的,只需要本模块负责初始化一次即可。通过以下代码我们可以看到angular通过minErr函数传入module参数,并在返回的闭包函数中引用module参数实现这一点。

//构造模块异常类,module为模块编码,ErrorConstructor异常构造函数

function minErr(module, ErrorConstructor) {

//如果未传入异常构造函数则使用Error

ErrorConstructor = ErrorConstructor || Error;

//返回异常对象构建方法

return function() {

};

}

这里需要注意的是传入参数ErrorConstructor,这里可以传入特定类型的异常类,比如ES6内置了RangeError、ReferenceError、SyntaxError、TypeError、URIError异常类型,这样我们就可以实现抛出特定类型的异常。但是我感觉这里不好的一点是无法实现模块内自由灵活的抛出不同的特定类型异常,其实这点可以在闭包函数参数中实现。

二、定义日志编码和日志信息模板

当我们每次记录日志的时候,需要传入日志编码及日志信息模板,方便记录异常发生的代码块及更具可读性的异常信息。通过以下的代码,我们可以看到angular通过闭包函数的可变参数的第一个参数定义日志编码,通过第二个参数定义日志信息模板。

//构造模块异常类,module为模块编码,ErrorConstructor异常构造函数

function minErr(module, ErrorConstructor) {

//如果未传入异常构造函数则使用Error

ErrorConstructor = ErrorConstructor || Error;

//返回异常对象构建方法,传入参数可变

return function() {

//日志编码,只能是第一个参数

var code = arguments[0],

//构造日志前缀

prefix = ‘[‘ + (module ? module + ‘:‘ : ‘‘) + code + ‘] ‘,

//日志模板

template = arguments[1],

//传入参数

templateArgs = arguments,

};

}

三、日志模板信息替换

通过传入日志相关对象来替换日志模板中的信息,从而形成更有意义的异常信息。通过以下代码我们可以看到angular通过replace方法实现日志模板中站位符的替换。

//模板信息替换

message = prefix + template.replace(/\{\d+\}/g, function(match) {

//获取站位符的索引,并转化为数字

var index = +match.slice(1, -1), arg;

//获取替换站位符的传入参数对象的字符串表示形式

if (index + 2 < templateArgs.length) {

//对象转换为字符串

return toDebugString(templateArgs[index + 2]);

}

return match;

});

在这里很巧妙的使用了string的replace方法,通过其正则表达式参数和生成替换字符串的方法实现模板中所有站位符的替换。replace的方法定义如下

stringObject.replace(regexp/substr,replacement)

参数


描述


regexp/substr


必需。规定子字符串或要替换的模式的RegExp 对象。

请注意,如果该值是一个字符串,则将它作为要检索的直接量文本模式,而不是首先被转换为RegExp 对象。


replacement


必需。一个字符串值。规定了替换文本或生成替换文本的函数。

在replacement方法里很巧妙的使用了string的slice方法,实现获取站位符索引。这里使用了两个技巧,其中的+号实现了字符串转化为数字,其中slice中传入的参数1和-1巧妙的提取了站位索引。slice的方法定义如下

stringObject.slice(start,end)

参数


描述


start


要抽取的片断的起始下标。如果是负数,则该参数规定的是从字符串的尾部开始算起的位置。也就是说,-1 指字符串的最后一个字符,-2 指倒数第二个字符,以此类推。


end


紧接着要抽取的片段的结尾的下标。若未指定此参数,则要提取的子串包括start 到原字符串结尾的字符串。如果该参数是负数,那么它规定的是从字符串的尾部开始算起的位置。

angular将传入的对象转化为便于调试的字符串形式,具体代码如下,其中函数对象会清空函数体,undefined变量直接返回undefined字符串,字符串则直接返回,其他类型对象则调用serializeObject进行序列化。这里需要注意对函数对象的处理,对匿名函数的处理并不尽如人意,这里我也没有想到更好的处理方式。

//将传入的对象转化为便于调试的字符串形式

function toDebugString(obj) {

//如果是函数则清空函数体

if (typeof obj === ‘function‘) {

return obj.toString().replace(/ \{[\s\S]*$/, ‘‘);

} else if (typeof obj === ‘undefined‘) {

return ‘undefined‘;

} else if (typeof obj !== ‘string‘) {//如果是非字符串的其他对象则进行序列化

return serializeObject(obj);

}

return obj;

}

angular将对象转化为json字符串的代码如下,其通过JSON的stringify方法的第二个方法参数控制键值对的序列化结果,同时也通过seen数组防止引用闭环导致序列化死循环。

//将对象转化为json字符串

function serializeObject(obj) {

var seen = [];

return JSON.stringify(obj, function(key, val) {

//获取val的具体字符串表示形式

val = toJsonReplacer(key, val);

//防止引用闭环导致死循环

if (isObject(val)) {

if (seen.indexOf(val) >= 0) return ‘<<already seen>>‘;

seen.push(val);

}

return val;

});

}

JSON.stringify的方法定义如下

JSON.stringify(value[, replacer[, space]])


参数


描述


value


待序列化为JSON字符串的对象


replacer


可传入数组定义序列化需要包含的属性,或者传入修改序列化行为的方法,如果不传入参数,则默认序列化所有的非方法属性。


space


分割符,具体参考以下

A String or Number object that‘s used to insert white space into the output JSON string for readability purposes. If this is a Number, it indicates the number of space characters to use as white space; this number is capped at 10 if it‘s larger than that. Values less than 1 indicate that no space should be used. If this is a String, the string (or the first 10 characters of the string, if it‘s longer than that) is used as white space. If this parameter is not provided (or is null), no white space is used.

angular针对内置一些复杂对象的序列化处理代码如下

//过滤对angular复杂对象的序列化

function toJsonReplacer(key, value) {

var val = value;

//两个$$开头的字符串返回undefined

if (typeof key === ‘string‘ && key.charAt(0) === ‘$‘ && key.charAt(1) === ‘$‘) {

val = undefined;

} else if (isWindow(value)) {//window

val = ‘$WINDOW‘;

} else if (value && document === value) {//document

val = ‘$DOCUMENT‘;

} else if (isScope(value)) {//scope

val = ‘$SCOPE‘;

}

return val;

}

四、构建在线错误链接

针对特定的异常能够提供在线解决方案是十分人性化的,angular默认提供跳转到angular的在线错误页面,我们可以根据实际需要替换为我们的。这里直接返回异常实例,方便调用者直接调用函数使用。

//构建错误在线链接

message = message + ‘\nhttp://errors.angularjs.org/1.3.9-local+sha.a3c3bf3/‘ +

(module ? module + ‘/‘ : ‘‘) + code;

for (i = 2; i < arguments.length; i++) {

message = message + (i == 2 ? ‘?‘ : ‘&‘) + ‘p‘ + (i - 2) + ‘=‘ +

encodeURIComponent(toDebugString(arguments[i]));

}

//构建异常错误实例

return new ErrorConstructor(message);

五、整个处理流程如下图所示

六、实际使用样例

调用代码如下

var codeartistminErr = minErr("CodeRrtist");

throw codeartistminErr("AngularExceptionDesinBlog",‘this is my AngularExceptionDesinBlog,{0}‘,{name:‘codeartist‘});

调用结果

添加注释的angular.js源代码文件下载地址

时间: 2024-11-05 23:22:52

angular代码设计之异常日志设计的相关文章

异常日志处理-ThrowsAdvice

有的时候,为了保全代码的简洁,我们不希望在程序中看到一些跟程序逻辑的代码,譬如异常日志打印,这个时候就需要我们对程序中的异常日志进行统一的管理.spring aop 可以在不破坏程序逻辑的情况下很好的完成我们上面的需求.本文对对日志的处理使用到了ThrowsAdvice接口和spring aop ThrowsAdvice接口 1 /* 2 * Copyright 2002-2008 the original author or authors. 3 * 4 * Licensed under th

Atitit.异常的设计原理与&#160;策略处理&#160;java&#160;最佳实践&#160;p93

Atitit.异常的设计原理与 策略处理 java 最佳实践 p93 1 异常方面的使用准则,答案是::2 1.1 普通项目优先使用异常取代返回值,如果开发类库方面的项目,最好异常机制与返回值都提供,由调用者决定使用哪种方式..2 1.2 优先把异常抛出到上层处理..异常本身就是为了方便把异常情况抛出到上层处理..2 1.3 对于 HYPERLINK \l _Toc6222 方法调用结果异常情况返回策略,最终会有四种策略状况,2 1.4 返回null  还是异常??2 2 异常的由来与设计3 2

【转】 C#学习笔记14——Trace、Debug和TraceSource的使用以及日志设计

[转] C#学习笔记14--Trace.Debug和TraceSource的使用以及日志设计 Trace.Debug和TraceSource的使用以及日志设计   .NET Framework 命名空间 System.Diagnostics 包含用于跟踪执行流程的 Trace.Debug 和 TraceSource 类,以及用于分析代码的 Process.EventLog 和 PerformanceCounter 类. 跟踪是一种在应用程序运行时监视其执行情况的方式.当开发 .NET Frame

Java异常框架设计

什么是异常? 异常(exception)应该是异常事件(exceptional event)的缩写.异常定义:异常是一个在程序执行期间发生的事件,它中断正在执行的程序的正常的指令流.当在一个方法中发生错误的时候,这个方法创建一个对象,并且把它传递给运行时系统.这个对象被叫做异常对象,它包含了有关错误的信息,这些信息包括错误的类型和在程序发生错误时的状态.创建一个错误对象并把它传递给运行时系统被叫做抛出异常.一个方法抛出异常后,运行时系统就会试着查找一些方法来处理它.这些处理异常的可能的方法的集合

Java日志设计&amp;实践(1) - 常见问题

日常开发.运维过程中经常会碰到以下几个问题: 什么情况下需要输出日志? 已明确需要输出日志时,如何选择日志级别? 已明确需要输出日志时,日志中需要输出哪些东东? 一个Tomcat加载多个工程,如何确定日志中的内容是哪个工程的? 多个Tomcat同时加载同一个工程,可以使用log4j的DailyRollingFileAppender等文件类Appender吗? 多个Tomcat同时加载同一个工程,可以分别指定日志输出目录吗? 日志中的中文乱码怎么办? 可以动态调整一个类的日志级别吗? 一天日志文件

ASP.NET全局错误处理和异常日志记录以及IIS配置自定义错误页面

应用场景和使用目的 很多时候,我们在访问页面的时候,由于程序异常.系统崩溃会导致出现黄页.在通常的情况下,黄页对于我们来说,帮助是极大的,因为它可以帮助我们知道问题根源,甚至是哪一行代码出现了错误.但这对于用户是非常可怕的,因为用户不知道发生了什么,也无法了解黄页给出的内容.甚至,如果我们遇到一些不友好的人,他们会拿这些内容大做文章,对我们网站产生威胁. 那我们如何在程序异常.系统崩溃时,不会出现黄页,并且还可以给出一些更加友好的提示呢?甚至在我们需要的时候,可以收集这些异常信息,并加以分析,能

[转载]针对IIS7以上的ASP.NET网站自定义错误页面与异常日志总结

针对IIS7以上的ASP.NET网站自定义错误页面与异常日志总结 汪宇杰 2014-1-11 星期六 02:31 455 Reads 1 Comments 自定义错误页面和异常记录是个很古老的话题了,但依旧可以让人爆到现在.在我做了无数次试验并总结经验和原则后,写下本文,已警后人. 本文的范围和限制 本文仅仅适用于部署在IIS7或以上版本中的ASP.NET 4.0集成模式应用程序.IIS7以上的意思是Windows Server 2008以上服务器适用.我已在WS2012R2,IIS8上测过.

SoC嵌入式软件架构设计之六:API设计方法

在嵌入式系统中,驱动都是以API的方式提供给应用进行调用.这里介绍嵌入式系统的API设计和管理方法. 驱动在系统中会按模块进行分类,例如按键驱动.LCD驱动.文件系统.card驱动.I2C驱动等等:每个模块又有多个接口,例如LCD驱动有光标定位.画点.画直线等,而文件系统有fread.fwrite.fseek.fopen等接口.以下举例将以文件系统的fopen为例,工具链为mips. 一.API设计方法 1. 驱动接口声明:extern FILE * fopen(const char * pat

转:使用log4net完成程序异常日志记录(使用SQLite数据库记录和普通文本记录)

http://www.cnblogs.com/kyo-yo/archive/2010/06/11/use-log4net-to-log-exception.html 在前端时间开发的时候由于需要将异常保存到数据库中,所以就到网上搜了下专门的日志记录工具,一搜果然很多,比如:log4net,NLog,EntLib Logging等等,但是还是log4net名气最大,所以就下载下来试用了一番,果然很方便,其涵盖了所有常用的日志记录方式具体的可以看下表: AdoNetAppender 将日志记录到数据