日志使用和规范

日志异常规范

1 前言
日志和异常处理是进行编程的日常任务,好的日志和异常处理能够在保持系统性能的同时有效提高问题诊断的效率。我们这个规范目的就是为了把日志和异常的处理进行规范化。

2 日志API的选择
在NC产品系统中,对日志的使用对象一般分为两类:基础技术和应用平台、业务产品。这三类使用对象对日志使用的关心有所不同。如何选取并使用适当的日志API满足不同使用对象的需求,我们描述如下:

2.1 基础技术和应用平台
基础技术的日志一方面要记录其自身的运行情况,又要为应用产品提供日志记录的初始化工作,因此需要按照下面的规范使用API:

Ø 记录只有基础技术平台自身关心的日志,使用nc.bs.logging.Log进行日志,如:

package nc.bs.demo.logging;

import nc.bs.logging.Log;

public class HelloWorld {
private static final Log log = Log.getInstance(HelloWorld.class);

public static void main(String args[]) {
	log.debug("Hello,World");
}

}
Ø 在调用应用产品代码,进入应用产品之前,之后需要调用nc.bs.logging.Logger的init和reset方法,进行应用产品日志入口的初始化

try {
Logger.init(service);
…//进入应用产品
} finally {
Logger.reset();
}
2.2 业务产品
业务产品只能使用API,nc.bs.logging.Logger,并且不能调用init和reset方法

2.3 日志级别使用
日志API中很大一类API的输出控制受日志级别的控制,选在正确的日志级别能够提高系统的性能,并使输出收到良好的控制。

目前规定日志只有四种日志级别DEBUG、INFO、 WARN、 ERROR,顺序为DEBUG<INFO、 <WARN<ERROR,如果日志级别调的较高,低级别的日志就不能输出如,设置位WARN,那么DEBUG与INFO的信息就不能输出。对四个级别的选择我们描述如下:

Ø DEBUG: 输出普通的调试信息,主要用于开发环境的信息输出

Ø INFO: 输出提示性的信息,如程序运行所花费的时间等

Ø WARN: 输出警告性的信息,如系统设置了一个需要打开的文件,但是系统在打开他的时候有问题,而用了一个缺省的文件,为此系统还是能够正常运行,但却不符合某些期望,采用警告

Ø ERROR: 错误信息输出,表示系统出了错误,影响了系统的功能,如系统抛出了一个NullPointException,系统不能正常运行。统运行时默认输出级别为ERROR

3 异常规范
3.1 异常定义
业务产品的异常必须继承BusinessException或BusinessRuntimeException,异常的定义必须严格的按照这个异常的层次进行。

如系统管理框架:

package nc.vo.sm.exception;
import nc.vo.pub.BusinessException;
public class SystemManagerException extends BusinessException {

}
该产品模块的异常都需要从这异常继承而来,如无效的用户异常:

package nc.vo.sm.exception.sm;

public class InvalidUserException extends SystemManagerException {

}

总结起来异常定义的规则如下:

Ø 产品模块定义两个基本异常(受查的和非受查的),该异常来自BusinessException或者BusinessRuntimException

Ø 该产品模块的所有的子异常来自这两个异常

Ø 异常包以<nc.vo.模块>作为基本的包头

Ø 所有的异常名称必须以Exception结尾

3.2 抛出和捕获的声明
代码中throws语句用来申明该方法所可能遇到的异常,总结起来,我们有下面的建议:

Ø 业务模块方法throws部分的受查异常都需要来自业务异常(BusinessException)和BusinessRuntimeException

Ø throws语句越细致越好,这样方法的异常出口就得到了充分的描述,代码更应该维护

Ø cach语句越细致越好,这样对各个异常的处理才能按照不同的异常进行更好的复合业务的处理。

4 日志异常的使用规范
一般来说为了排查系统问题,异常都伴有日志的过程,因此我们这一章节把日志和异常使用上的规范综合起来进行说明。

4.1 一般性的要求
Ø 在所有业务组的代码中严禁出现System.out.println()代码

Ø 如果日志输出不要求在运行时刻发生变化,用Log,它具有更高的效率,中间件组的纯技术代码使用,其它开发不需使用

Ø 基础算法的程序(供给所有模块使用),统一采用Logger作为API

Ø 后台业务程序和前后台公共程序、全部业务程序采用Logger

Ø 平台类级程序需要在进入应用产品代码的过程中,进行采用Logger.init/reset设置,遵循有init就必须reset的原则

Ø 应用程序一般不需要关心运行时刻异常(RuntimeException及子类)或者错误(Error或者子类)

Ø DbException和SQLException都是受查异常,业务系统在捕作后,如果不能按照逻辑正常地进行处理,直接转化为产品模块的业务异常,进行抛出,不需要保持异常链,注意在抛出异常之前需要进行日志工作

Ø 如果异常已经在throws语句中抛出,一般不需要进行捕捉和处理

Ø 如果在异常处理上,不知道是否要抛出什么样的异常,那么最好按照接口的要求抛出BusinessException体系下的异常,而不是运行时刻的异常

Ø 不能抛出没有任何业务意义的异常如throw new Exception(“msg”)

Ø 如果异常需要抛出给前端应用(ui),出于安全的考虑可能不希望前端程序保留异常的链,这时候需要首先日志改异常,然后把该异常转化为业务异常,去掉异常链抛出

Ø 如果捕捉到异常后,不会再次把异常抛出(吃点异常),如果有跟踪的必要性对异常进行日志工作,日志的级别根据业务逻辑可以选用debug或者warn。对于对系统的表现有一定影响的采用warn,而几乎没有影响的采用debug

Ø 如果捕捉了InvokeTragetException,不能把该异常直接抛出,而是需要对其中的目标异常进行处理(getTargetException())

Ø 中间件抛出的SystemException, NamingException异常应用程序捕捉后首先进行日志,然后转化为BusinessException/BusinessRuntimeException的子类,不需要保持异常链

Ø SQLException必须进行捕捉和处理,进行日志处理,并且转化为对应的BusinessException/BusinessRuntimeException的子类,不需要保持异常链

Ø 如果捕捉到的异常,处理重新包装抛出异常,去掉了异常链,对原始异常应该首先进行日志

Ø 如果异常抛出后,保持了异常链,在抛出之前对原始的异常不需要进行日志工作

Ø 程序中不要抛出NullpointException,例如throw new NullpointException(“test”)

Ø

示例如下:

package nc.bs.demo.finance;

import nc.bs.demo.hr.HRException;
import nc.bs.demo.hr.IHRService;
import nc.bs.demo.supply.ISupplyService;
import nc.bs.demo.supply.SupplyException;
import nc.bs.framework.common.NCLocator;
import nc.bs.framework.exception.ComponentException;
import nc.bs.logging.Log;
import nc.vo.pub.BusinessRuntimeException;

public class SampleBServiceImpl {
// 根据需要选择适合的日志API,如果动态日志采用Logger
private static final Log log = Log.getInstance(SampleBServiceImpl.class);

public void service(String account) throws FinanceException {

try {
NCLocator l = NCLocator.getInstance()
ISupplyService supplyService =l.lookup(ISupplyService.class);
supplyService.service(account);
IFinanceService finService = l.lookup(IFinanceService.class);
finService.balance(account);
IHRService hrService =l.lookup(IHRService.class.getName());
hrService.service();
} catch (ComponentException e) {
//该异常作为业务处理经常要面对的异常因此我们做一些包装,但是我们不希望抛出
//去的异常暴露我们的非业务的异常链,因此首先日志它,然后重新包装出去
log.error(“处理账户:” + account + " 出现错误", e);
throw new FinanceException("所要的服务没有安装,请购买该服务模块: " + IFinanceService.class);
//e.printStackTrace();
} catch (FinanceException e) {
//异常为本模块业务的异常,因此抛出,一般情况下不用捕捉该异常
throw e;
} catch (SupplyException e) {
//其他模块的业务异常,包装抛出,保持异常链
throw new FinanceException(“服务失败”, e);
} catch(NullPointerException e) {
//特别的异常处理,预料之外的异常,包装抛出,保持异常链,也可以根据需要抛出为BusinessRuntimeExcepiton的模块子类异常
throw new FinanceException(“服务失败”, e);
//throw new FinanceRuntimeException(“服务失败”, e);
} catch (HRException e) {
//该异常对业务没有任何影响,因此我们吃掉该异常,但是为了跟踪,我们需要日志
log.debug(“通知人力资源失败:” + e.getMessage());
//如果改行为比较要紧采用警告
//log.warn(“通知人力资源失败”, e);
} catch(BusinessRuntimeException e) {
//最普通的异常放在最后面处理,这里我们需要对BusinessRunitmeException进行处理
//log.error(“服务失败”, e);
throw new FinanceException(“服务失败”, e);
}

}
}

  • 20
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值