首页 > 代码库 > 良好的日志记录规范

良好的日志记录规范

平常我的系统开发运行过程中,记录关键信息对于完善和修改提出了明确的建议。但是在现实的一些应用中的日志记录比较混乱,导致无法准确快速的定位问题发生的地方和问题发生的时候以及问题发生的场景。我就依据我平时使用log4j进行日志记录的一点心得与大家分享如何更加规范的记录日志信息,如果有不妥的问题请明示我好进行相应的改进,共同进步哈。

1.要记录什么类型日志

我们的系统开发常常会涉及到系统致命错误日志,系统可控错误日志,用户操作日志和系统运行日志这四大类日志的记录。记录致命性错误用于记录会影响整个系统正常运行的错误,比如我们在开发过程中的try...catch...模块中抛出的一些未能预料到的系统错误,而且这种错误会导致系统运行失败的信息进行记录。系统可控错误日志,这一类的日志发生之后其实不会导致系统运行出现异常的,可能是对某些数据的初始化深入验证出现的问题。用户操作日志这一类日志量比较大,同时这一类日志用于跟踪用户的行为分析是非常的重要的应为可以作为用户数据挖掘发现用户的喜好等一些信息。程序运行信息记录,这一类信息用于记录子过程运行情况。

2.致命错误如何记录

如上所述我们明确的错误日志,是用来记录系统费预测性错误,可能导致网站爆出黄页相应的操作流程无法进行下去。或则在一些安装程序中记录导致系统突然退出的相关信息。在防御式编程中经常使用try....catch...模块包括一个程序的运行过程,catch的最后捕获的一级Exception是我们无法控制也无法预测的系统运行异常,这里我们记录fatal致命性错误,我这里一般记录的是一场发生的堆栈信息。如下程序块:

try {
			VerificationUser(user);
			String result = OrderTicket(user,flight);
			orderticket.trace("执行占座成功!占座成功的代码:"+result);
			orderticket.info(user.getName()+"执行了占座操作,占座编码为"+result);
			String ticketNo= GenariteTicket(result);
			genariteTicket.trace("执行出票成功!出票成功票号:"+ticketNo);
			genariteTicket.info(user.getName()+"执行了生成票功能:票号:"+ticketNo);
		} 
		catch (Exception e) {
			// fatal
			genariteTicket.fatal(e.getStackTrace());
			throw e;
		}


完成这样的日志记录,当程序再次发生异常之后就可以快速定位致命性错误发生的位置和相应的异常信息。


3.可预料错误如何记录

大家可能还比较迷茫为什么我们的可预料错误还需要记录日志呢?这样理解吧,假设如下场景,一个旅客订机票但是当提交订单的瞬间机票已经售完,相应的订票系统会直接返回一个订票异常,按普通设想我们需要屏蔽这种异常然后自己封装一个更好的提示展示给用户就ok了,但是为了更好的分析什么情况下什么时间点机票就已经售完或超售了所以这一类信息作为我们的可控制信息那么我们需要进行相应的日志记录。

try {
			VerificationUser(user);
			String result = OrderTicket(user,flight);
			orderticket.trace("执行占座成功!占座成功的代码:"+result);
			orderticket.info(user.getName()+"执行了占座操作,占座编码为"+result);
			String ticketNo= GenariteTicket(result);
			genariteTicket.trace("执行出票成功!出票成功票号:"+ticketNo);
			genariteTicket.info(user.getName()+"执行了生成票功能:票号:"+ticketNo);
		}catch(VerificationException e){
			//error
			orderticket.error(e.getMessage());
			throw e;
		} 


4.用户操作日志如何记录

用户操作日志是一块重头,应为它记录频繁而且记录信息量较大。在一般的网络程序中记录用户的操作日志尽量不要浪费系统的额外性能开销,降低系统的消耗,但是我们记录的信息要方便下一步的数据挖掘用户行为分析(我设想我们要记录的数据应该是结构化的数据)。用户操作数据面临数据结构异常多,数据流量非常大,数据价值如何提高等这些问题。

第一个问题:定义统一的数据结构,这样做的目的是为了能够方便使用相应的工具进行用户操作日志挖掘,这个就是不同的公司有不同的标准。如果要进行实时性高的用户日志分析可采用splink或则建立大数据处理平台离线流处理平台。另外介绍两款大数据处理平台impala作为一款交互式数据分析平台实时性也很高,Storm作为一种流处理平台在数据分析统计上面有独到的优势。

第二个问题:频繁记录日志会导致系统IO的消耗,我们可以采用Redis或memcached这一类内出数据库先行记录日志当量达到一定规模自动记录到日志文件中避免平凡调用IO进行文件数据写入或数据库写入。

第三个问题:提高用户数据价值,目的是为了提高分析用户数据,分析用户数据是为了分析出一种或几种用户行为模式。要做到易于分析用户模式需要建立相应的操作日志记录结构,规定好结构进行分析就降低了复杂度。

用户日志分析有以下几点好处:

1.高价值用户挖掘。

2.高价值航班挖掘。

3.客户偏好收集,为了下一步进行客户建模,然后提供贴心的服务。

4.产品捆绑式销售,来自对客户的建模之后。

5.发觉公司的节点性人物,这种人物可以把公司扩展到其他的领域或其他的圈子里面。

6.发觉社会影响力大的任务,比如网络大V,这种人的影响力非常大。

有了这些结果,就可以体现用户日志价值,并尽快制定符合自己公司的记录结构。

5.调试跟踪日志如何记录

这一类日志在与单机程序调试不是十分的方便,程序连调的时候不易断点跟踪。使用日志记录可以代替断点跟踪,记录程序每一个子过程运行情况,如下我使用trace记录了每一个子过程的运行情况。

try {
			VerificationUser(user);
			String result = OrderTicket(user,flight);
			orderticket.trace("执行占座成功!占座成功的代码:"+result);
			orderticket.info(user.getName()+"执行了占座操作,占座编码为"+result);
			String ticketNo= GenariteTicket(result);
			genariteTicket.trace("执行出票成功!出票成功票号:"+ticketNo);
			genariteTicket.info(user.getName()+"执行了生成票功能:票号:"+ticketNo);
		}catch(VerificationException e){
			//error
			orderticket.error(e.getMessage());
			throw e;
		} 
		catch (Exception e) {
			// fatal
			genariteTicket.fatal(e.getStackTrace());
			throw e;
		}


6.一些小建议可以方便我们更好的做好日志记录

1.当程序产生异常时,必须捕捉并处理异常、将异常记录到日志中(除非打算抛出异常)。

 2.不要处理能够避免的异常。

 3.在异常处理模块中提供适量的错误原因信息。

 4.不要从try区段中返回。

  5.将try/catch区段置于循环之外。

  6.不要将异常用于程序流程控制。

  7.记录异常不要保存exception.getMessage(),而要记录exception.toString().

  8.一个方法不应抛出太多类型的异常。说明:如果程序中需要分类处理,则将异常根据分类组织成继承关系。如果确实有很多异常类型首先考虑用异常描述来区别,throws/exception子句标明的异常最好不要超过三个。

 9.异常捕获尽量不要直接catch(Exceptionex),应该把异常细分处理。

10. 尽量减小try块的体积。

11. 尽量抛出异常,顶层的main()函数截获所有的异常,并且打印(或者记录在日志中)在屏幕上。


良好的日志记录规范