关于异常,在排查问题的时候,日志对于我们显的格外重要,前几天发布的时候就遇到一个悲剧的现象,发布beta测试的时候,发现有个NullPointException,但是日志中只有日志的类全名称,但是没有栈信息以及代码行号,无法定位哪一行跑出来的,于是只能重新改代码,十分之蛋疼。于是把日志相关的东西扫一下雷。
---------------------------------------------------------------------------------------------------------------------
日志系统
Log4j —— 较早出现的比较成功的日志系统是Log4j。Log4j开创的日志系统模型(Logger/Appender/Level)行之有效,并一直延用至今。
JUL(java.util.logging.*) —— JDK1.4是第一个自带日志系统的JDK,简称(JUL)。JUL并没有明显的优势来战胜Log4j,反而造成了标准的混乱 —— 采用不同日志系统的应用程序无法和谐共存。
Logback —— 是较新的日志系统。它是Log4j的作者吸取多年的经验教训以后重新做出的一套系统。它的使用更方便,功能更强,而且性能也更高。Logback不能单独使用,必须配合日志框架SLF4J来使用。
-----------------------------------------------------------------------------------------------------------------------
引用一篇文章中关于java log的描述。
为了克服多种日志系统并存所带来的混乱,就出现了“日志框架”。日志框架本身不提供记录日志的功能,它只提供了日志调用的接口。基本可以理解,log4j作为log信息的配置,就是日志打在哪里,怎么打等,然后有开源jar包提供了访问日志文件的接口,用来和具体的日志系统解耦,例如commmon-logging和slf4j,提供了LogFactory来获取具体的log对象,获取了log对象后,就可以打日志了。下面是两个常用的日志框架
(1)commons-logging,apache提供的日志门面接口,主要是为了避免程序和具体的log耦合。首先需要引入commons-logging.jar(通过maven或者其他方法皆可),然后这样使用就可以了
<!--[if !supportLists]-->1. <!--[endif]-->Log logger = LogFactory.getLog(TestCommonsLogging.class);
<!--[if !supportLists]-->2. <!--[endif]-->logger.debug(“test debug”);
(2)slf4j和commons-logging功能类似,首先要引入slf4j-api-1.6.4jar,然后比如要支持log4j,就引入slf4j-log4j12-1.6.4jar
Logger logger = LoggerFactory.getLogger(Slf4jTest.class);
logger.debug(“test debug”);
<!--EndFragment-->-----------------------------------------------------------------------------------------------------------------------
Log4j的几个概念:
(1)layout:一行日志的格式,正则形式
org.apache.log4j.HTMLLayout(以HTML表格形式布局),
org.apache.log4j.PatternLayout(可以灵活地指定布局模式),
%p: 输出日志信息优先级,即DEBUG,INFO,WARN,ERROR,FATAL,
%d: 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},
%r: 输出自应用启动到输出该log信息耗费的毫秒数
%c: 输出日志信息所属的类目,通常就是所在类的全名
%t: 输出产生该日志事件的线程名
%l: 输出日志事件的发生位置,
%x: 输出和当前线程相关联的NDC(嵌套诊断环境),尤其用到像java servlets这样的多客户多线程的应用中。
%%: 输出一个"%"字符
%F: 输出日志消息产生时所在的文件名称
%L: 输出代码中的行号
%m: 输出代码中指定的消息,产生的日志具体信息
%n: 输出一个回车换行符,
org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串),
org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)
如果需要线程信息,可以加上%t来获取这个信息
(2)appender:输出日志的位置信息
org.apache.log4j.ConsoleAppender(控制台),
org.apache.log4j.FileAppender(文件),
org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件),
org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件),
org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)
(3)level:日志输出等级,共五级,DEBUG/INFO/WARN/ERROR/FATAL
-----------------------------------------------------------------------------------------------------------------------
日志中没有异常栈信息:
JDK5之后JVM有个优化,就是如果一个异常抛出一段时间后,为了性能考虑,后续就不会再抛出stackTrace信息,当然这个功能也可以通过JVM的启动参数来去掉:-XX:-OmitStackTraceInFastThrow.
-----------------------------------------------------------------------------------------------------------------------
关于Throwable
(1)getCause()
获取这个抛出的原因;
(2)getMessage()
获取这个抛出的描述信息,例如throw new Exception("我是抛出来的异常"),
这时候次方法会返回括号里面的文本信息
(3)getStackTrace()
获取抛出的栈信息,printStackTrace()能够打印栈信息。
logger.error("i am zhongyong",e); 输出文本信息以及异常栈信息
logger.error(e); 只是返回异常的名称信息,栈信息没有
-----------------------------------------------------------------------------------------------------------------------
异常转型在上面已经提到过了,实际上就是捕获到异常后,将异常以新的类型的异常再抛出,这样做一般为了异常的信息更直观!比如:
public void run() throws MyException{
...
try{
...
}catch(IOException e){
...
throw new MyException();
}finally{
...
}
}
在throw new MyException()时候,建议MyException(e),否则就会出现异常被吃掉的情况。
-----------------------------------------------------------------------------------------------------------------------
对于运行时异常,我们不要用try...catch来捕获处理,而是在程序开发调试阶段,尽量去避免这种异常,一旦发现该异常,正确的做法就会改进程序设计的代码和实现方式,修改程序中的错误,从而避免这种异常。捕获并处理运行时异常是好的解决办法,因为可以通过改进代码实现来避免该种异常的发生。
对于受检查异常,没说的,老老实实去按照异常处理的方法去处理,要么用try...catch捕获并解决,要么用throws抛出!
对于Error(运行时错误),不需要在程序中做任何处理,出现问题后,应该在程序在外的地方找问题,然后解决。
1、避免过大的try块,不要把不会出现异常的代码放到try块里面,尽量保持一个try块对应一个或多个异常。
2、细化异常的类型,不要不管什么类型的异常都写成Excetpion。
3、catch块尽量保持一个块捕获一类异常,不要忽略捕获的异常,捕获到后要么处理,要么转译,要么重新抛出新类型的异常。
4、不要把自己能处理的异常抛给别人。
5、不要用try...catch参与控制程序流程,异常控制的根本目的是处理程序的非正常情况。
-----------------------------------------------------------------------------------------------------------------------