异常框架-异常链和log4j

本文深入探讨了Java异常链的概念及其在实际编程中的应用,并详细介绍了如何利用Log4j进行高效的日志管理,包括异常信息的单独输出、通过不同日志级别配置实现异常通知以及在后台输出所有类别错误的方法。通过实践案例,展示了如何在代码中正确地处理异常并将其记录到不同的日志文件中,以辅助调试和维护。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

异常链
2010-03-09 20:18

 

package test;  

/**
*  
* @author jenhy
*
*/


class HighLevelException extends Exception{


HighLevelException(Exception e){
   super(e);
}
}

class MiddleLevelException extends Exception{

MiddleLevelException(Exception e){
   super(e);
}
}

class LowLevelException extends Exception{

LowLevelException(){
   super();
}

LowLevelException(Exception e){
   super(e);
}
}

public class ExceptionTest {  

    /**
     *  
     * @throws HighLevelException
     */
    public void highLevelAccess() throws HighLevelException {  
        try {  
            middleLevelAccess();  
        } catch (Exception e) {  
            throw new HighLevelException(e);  
        }  
    }  

    /**
     *  
     * @throws MiddleLevelException
     */
    public void middleLevelAccess() throws MiddleLevelException {  
        try {  
            lowLevelAccess();  
        } catch (Exception e) {  
            throw new MiddleLevelException(e);  
        }  
    }  

    /**
     *  
     * @throws LowLevelException
     */
    public void lowLevelAccess() throws LowLevelException {  
        throw new LowLevelException();  
    }  

    /**
     *  
     * @param args
     */
    public static void main(String[] args) {  
        try {  
            new ExceptionTest().highLevelAccess();  
        } catch (HighLevelException 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();  
            }  
        }  
    }  

}

 

当程序捕获到了一个底层异常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已经提供了这样的功能,我们只需要在配置中修改AppenderThreshold
就能实现,比如下面的例子:

[配置文件]

[代码中使用]

### 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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值