异常框架-异常链和log4j
??????????????? //打印堆栈??
??????????????? StackTraceElement[] ste = cause.getStackTrace();??
??????????????? for (int i = 0; i < ste.length; i++) {??
??????????????????? System.out.println("ClassName" + i + ":" + ste[i].getClassName() + "\nMethodName:" + ste[i].getMethodName() + "\nFileName:" + ste[i].getMethodName() + "\nLineNumber:" + ste[i].getLineNumber());??
??????????????????? System.out.println();??
??????????????? }??
??????????????? //递归??
??????????????? cause = cause.getCause();??
??????????? }??
??????? }??
??? }??
}
?
当程序捕获到了一个底层异常le,在处理部分选择了继续抛出一个更高级别的新异常给此方法的调用者。这样异常的原因就会逐层传递。这样,位于高层的异常递 归调用getCause()方法,就可以遍历各层的异常原因。这就是Java异常链的原理。异常链的实际应用很少,发生异常时候逐层上抛不是个好注意,上 层拿到这些异常又能奈之何?而且异常逐层上抛会消耗大量资源,因为要保存一个完整的异常链信息。
?
实践中的异常框架:
?
package cn.java.exception;
/**
?*
?* @author jenhy
?*
?*/
public class ExceptionTest {
?/**
? *
? * @throws Exception
? */
?public void highLevelAccess() throws Exception {
??try {
???middleLevelAccess();
??} catch (Exception e) {
//???throw new HighLevelException(e);
???throw e;
??}
?}
?/**
? *
? * @throws MiddleLevelException
? */
?public void middleLevelAccess() throws Exception {
??try {
???lowLevelAccess();
??} catch (Exception e) {
//???throw new MiddleLevelException(e);
???throw e;
??}
?}
?/**
? *
? * @throws LowLevelException
? */
?public void lowLevelAccess() throws Exception {
//??throw new LowLevelException();
??throw new RuntimeException();
?}
?/**
? *
? * @param args
? */
?public static void main(String[] args) {
??try {
???new ExceptionTest().highLevelAccess();
??} catch (Exception e) {
???Throwable cause = e;
???for (;;) {
????if (cause == null)
?????break;
????//打印Cause by
????System.out.println("Caused by: " + cause.getClass().getName() + ":" + cause.getMessage());
????//打印堆栈
????StackTraceElement[] ste = cause.getStackTrace();
????for (int i = 0; i < ste.length; i++) {
?????System.out.println("ClassName" + i + ":" + ste[i].getClassName() + "/nMethodName:" + ste[i].getMethodName() + "/nFileName:" + ste[i].getMethodName() + "/nLineNumber:" + ste[i].getLineNumber());
?????System.out.println();
????}
????//递归
????cause = cause.getCause();
???}
??}
?}
}
这样可以不用一层套一层的使用自定义的异常类,可以直接把异常信息通过log4j放入到文件中。
log4j 详解:
Log4J的配置文件(Configuration File)就是用来设置记录器的级别、存放器和布局的,它可接key=value格式的设置或xml格式的设置信息。通过配置,可以创建出Log4J的运行环境。
1. 配置文件
?[level] 是日志输出级别,共有5级:
FATAL?????? 0 ?
ERROR????? 3 ?
WARN?????? 4 ?
INFO???????? 6 ?
DEBUG????? 7
Appender
org.apache.log4j.ConsoleAppender(控制台),
org.apache.log4j.FileAppender(文件),
org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件),
org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件),
org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方) ?
?
org.apache.log4j.HTMLLayout(以HTML表格形式布局),
org.apache.log4j.PatternLayout(可以灵活地指定布局模式),
org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串),
org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)
打印参数: Log4J采用类似C语言中的printf函数的打印格式格式化日志信息,如下:
? %m?? 输出代码中指定的消息
%p?? 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL?
%r?? 输出自应用启动到输出该log信息耗费的毫秒数?
%c?? 输出所属的类目,通常就是所在类的全名?
%t?? 输出产生该日志事件的线程名?
%n?? 输出一个回车换行符,Windows平台为“/r/n”,Unix平台为“/n”?
%d?? 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy?MMM?dd?HH:mm:ss , SSS},输出类似:2002年10月18日? 22 : 10 : 28 , 921 ?
%l?? 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java: 10 )?
2. 为不同的 Appender 设置日志输出级别:
当调试系统时,我们往往注意的只是异常级别的日志输出,但是通常所有级别的输出都是放在一个文件里的,如果日志输出的级别是BUG!?那就慢慢去找吧。
这时我们也许会想要是能把异常信息单独输出到一个文件里该多好啊。当然可以,Log4j已经提供了这样的功能,我们只需要在配置中修改Appender的Threshold 就能实现,比如下面的例子:
[配置文件]
[代码中使用]
###?set?log?levels?###
log4j.rootLogger = debug , ?stdout , ?D , ?E
###?输出到控制台?###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = ?%d{ABSOLUTE}?%5p?%c{ 1 }:%L?-?%m%n
###?输出到日志文件?###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG?##?输出DEBUG级别以上的日志
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd?HH:mm:ss}? [ %t:%r ] - [ %p ] ?%m%n
###?保存异常信息到单独文件?###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = logs/error.log?##?异常日志文件名
log4j.appender.D.Append = true
log4j.appender.D.Threshold = ERROR?##?只输出ERROR级别以上的日志!!!
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd?HH:mm:ss}? [ %t:%r ] - [ %p ] ?%m%n ?
?
public ? class ?TestLog4j?
{
???? public ? static ? void ?main(String[]?args)?
{
????????PropertyConfigurator.configure( " D:/Code/conf/log4j.properties " );
????????Logger?logger? = ?Logger.getLogger(TestLog4j. class );
????????logger.debug( " debug " );
????????logger.error( " error " );
????}
}
运行一下,看看异常信息是不是保存在了一个单独的文件error.log中
高级使用
实验目的:
?1.把FATAL级错误写入2000NT日志
?2. WARN,ERROR,FATAL级错误发送email通知管理员
?3.其他级别的错误直接在后台输出
实验步骤:
?输出到2000NT日志
?1.把Log4j压缩包里的NTEventLogAppender.dll拷到WINNT/SYSTEM32目录下
?2.写配置文件log4j.properties
# 在2000系统日志输出
?log4j.logger.NTlog=FATAL, A8
?# APPENDER A8
?log4j.appender.A8=org.apache.log4j.nt.NTEventLogAppender
?log4j.appender.A8.Source=JavaTest
?log4j.appender.A8.layout=org.apache.log4j.PatternLayout
?log4j.appender.A8.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n
3.调用代码:
?Logger logger2 = Logger.getLogger("NTlog"); //要和配置文件中设置的名字相同
?logger2.debug("debug!!!");
?logger2.info("info!!!");
?logger2.warn("warn!!!");
?logger2.error("error!!!");
?//只有这个错误才会写入2000日志
?logger2.fatal("fatal!!!");
发送email通知管理员:
?1. 首先下载JavaMail和JAF,
? http://java.sun.com/j2ee/ja/javamail/index.html
? http://java.sun.com/beans/glasgow/jaf.html
?在项目中引用mail.jar和activation.jar。
?2. 写配置文件
?# 将日志发送到email
?log4j.logger.MailLog=WARN,A5
?#? APPENDER A5
?log4j.appender.A5=org.apache.log4j.net.SMTPAppender
?log4j.appender.A5.BufferSize=5
?log4j.appender.A5.To=chunjie@yeqiangwei.com
?log4j.appender.A5.From=error@yeqiangwei.com
?log4j.appender.A5.Subject=ErrorLog
?log4j.appender.A5.SMTPHost=smtp.263.net
?log4j.appender.A5.layout=org.apache.log4j.PatternLayout
?log4j.appender.A5.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n
?3.调用代码:
?//把日志发送到mail
?Logger logger3 = Logger.getLogger("MailLog");
?logger3.warn("warn!!!");
?logger3.error("error!!!");
?logger3.fatal("fatal!!!");
在后台输出所有类别的错误:
?1. 写配置文件
?# 在后台输出
?log4j.logger.console=DEBUG, A1
?# APPENDER A1
?log4j.appender.A1=org.apache.log4j.ConsoleAppender
?log4j.appender.A1.layout=org.apache.log4j.PatternLayout
?log4j.appender.A1.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n
?2.调用代码
?Logger logger1 = Logger.getLogger("console");
?logger1.debug("debug!!!");
?logger1.info("info!!!");
?logger1.warn("warn!!!");
?logger1.error("error!!!");
?logger1.fatal("fatal!!!");
--------------------------------
?全部配置文件:log4j.properties
?# 在后台输出
?log4j.logger.console=DEBUG, A1
?# APPENDER A1
?log4j.appender.A1=org.apache.log4j.ConsoleAppender
?log4j.appender.A1.layout=org.apache.log4j.PatternLayout
?log4j.appender.A1.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n
# 在2000系统日志输出
?log4j.logger.NTlog=FATAL, A8
?# APPENDER A8
?log4j.appender.A8=org.apache.log4j.nt.NTEventLogAppender
?log4j.appender.A8.Source=JavaTest
?log4j.appender.A8.layout=org.apache.log4j.PatternLayout
?log4j.appender.A8.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n
# 将日志发送到email
?log4j.logger.MailLog=WARN,A5
?#? APPENDER A5
?log4j.appender.A5=org.apache.log4j.net.SMTPAppender
?log4j.appender.A5.BufferSize=5
?log4j.appender.A5.To=chunjie@yeqiangwei.com
?log4j.appender.A5.From=error@yeqiangwei.com
?log4j.appender.A5.Subject=ErrorLog
?log4j.appender.A5.SMTPHost=smtp.263.net
?log4j.appender.A5.layout=org.apache.log4j.PatternLayout
?log4j.appender.A5.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n
全部代码:Log4jTest.java
?
/*
? * 创建日期 2003-11-13
? */
?package edu.bcu.Bean;
?import org.apache.log4j.*;
?//import org.apache.log4j.nt.*;
?//import org.apache.log4j.net.*;
?/**
? * @author yanxu
? */
?public class Log4jTest
?{
? public static void main(String args[])
? {
?? PropertyConfigurator.configure("log4j.properties");
?? //在后台输出
?? Logger logger1 = Logger.getLogger("console");
?? logger1.debug("debug!!!");
?? logger1.info("info!!!");
?? logger1.warn("warn!!!");
?? logger1.error("error!!!");
?? logger1.fatal("fatal!!!");
//在NT系统日志输出
?? Logger logger2 = Logger.getLogger("NTlog");
?? //NTEventLogAppender nla = new NTEventLogAppender();
?? logger2.debug("debug!!!");
?? logger2.info("info!!!");
?? logger2.warn("warn!!!");
?? logger2.error("error!!!");
?? //只有这个错误才会写入2000日志
?? logger2.fatal("fatal!!!");
//把日志发送到mail
?? Logger logger3 = Logger.getLogger("MailLog");
?? //SMTPAppender sa = new SMTPAppender();
?? logger3.warn("warn!!!");
?? logger3.error("error!!!");
?? logger3.fatal("fatal!!!");
? }
?}
?
?
使用log4j来实践error和info输出到不同的文件中:
Log4jConfigTest.java
?
package logging;
import org.apache.log4j.Logger;
public class Log4jConfigTest {
?public static final Logger logger=Logger.getLogger(Log4jConfigTest.class);
?public void highLevelAccess() throws Exception {
??try {
???middleLevelAccess();
??} catch (Exception e) {
???throw e;
??}
?}
??
?public void middleLevelAccess() throws Exception {
??try {
???lowLevelAccess();
??} catch (Exception e) {
???throw e;
??}
?}
?
?public void lowLevelAccess() throws Exception {
??throw new RuntimeException();
?}
?public static void main(String[] args) {
?? Log4jConfigTest lc=null;
??try{
???lc=new Log4jConfigTest();
???lc.highLevelAccess();
??} catch (Exception e) {
???//两个处理,为用户:提示错误信息,为程序员:提供错误具体位置。
???Throwable cause = e;
???for (;;) {
????if (cause == null)
?????break;
????LogFactory.infoLogger.info("Caused by: " + cause.getClass().getName() + ":" + cause.getMessage());
????LogFactory.errorLogger.error("Caused by: " + cause.getClass().getName() + ":" + cause.getMessage());
????//打印堆栈
????StackTraceElement[] ste = cause.getStackTrace();
????for (int i = 0; i < ste.length; i++) {
?????LogFactory.infoLogger.info("异常链" + i + ":" + ste[i].getClassName() + "/nMethodName:" + ste[i].getMethodName() +"/nLineNumber:" + ste[i].getLineNumber());
?????LogFactory.errorLogger.error("异常链" + i + ":" + ste[i].getClassName() + "/nMethodName:" + ste[i].getMethodName() +"/nLineNumber:" + ste[i].getLineNumber());
????}
????//递归
????cause = cause.getCause();
???}
??}
? }
}
?
?
LogFactory.java
package logging;
import java.io.File;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.log4j.FileAppender;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.SimpleLayout;
public class LogFactory { //设定两个Log
????? public static Logger infoLogger = Logger.getLogger("info.logger");
????? public static Logger errorLogger = Logger.getLogger("error.logger");
????? public static final String PROFILE = "log4j.properties";
???? //设定异常log输出的路径
?????? private static final String PATH = "D:\\";
????????? static{
????????????????? try{
????????????????????? URL configFileResource = (new File(LogFactory.class.getResource("/").getPath()+PROFILE)).toURL();??????????
????????????????????? PropertyConfigurator.configure(configFileResource);?
??????????????? }catch(Exception e){
???????????????????? e.printStackTrace();
?????????? }
???????? }
????? public LogFactory(){
???????????? try {
???????????????????????? Date date = new Date();
??????????????????????? SimpleDateFormat sf = new SimpleDateFormat("yyyyMMddHHmmss");
??????????????????????? String fileName = PATH + "exception_" + sf.format(date).toString() + ".log";
??????????????????????????? FileAppender exceptionAppender = new FileAppender(new SimpleLayout(), fileName);??????
???????????????????????? errorLogger.addAppender(exceptionAppender);
????????????????????? } catch (Exception e) {
????????????????????????????? e.printStackTrace();
???????????????????? }
?????????????????? }
???????? }
Log4j.properties
?
log4j.category.info.logger=INFO,info
log4j.category.error.logger=ERROR,error
log4j.appender.info = org.apache.log4j.FileAppender
log4j.appender.info.File=D:\\logs\\loginfo.log
log4j.appender.info.MaxFileSize=100kb
log4j.appender.info.MaxBackupIndex=4
log4j.appender.info.layout=org.apache.log4j.PatternLayout
log4j.appender.info.layout.ConversionPattern=%d{yyyy/MM/dd HH:mm:ss.SSS} %-5p %m%n log4j.appender.error=org.apache.log4j.RollingFileAppender
log4j.appender.error = org.apache.log4j.FileAppender
log4j.appender.error.File=D:\\logs\\error.log
log4j.appender.error.MaxFileSize=100kb
log4j.appender.error.MaxBackupIndex=4
log4j.appender.error.layout=org.apache.log4j.PatternLayout
log4j.appender.error.layout.ConversionPattern=%d{yyyy/MM/dd HH:mm:ss.SSS} %-5p %m%n
?
public ? class ?TestLog4j?
???? public ? static ? void ?main(String[]?args)?