log4j

 Log4j建议只使用四个级别,优先级从高到低分别是ERROR、WARN、INFO、DEBUG。比如在这里定义了INFO级别,只有等于及高于这个级别的才进行处理,

   一、log4j使用步骤(重点在使用过程和初始化):
1.将log4j.jar相关包放到jsp-examplesWEB-INFlib下;
2.在classpath下面建立log4j.properties;
3.完善log4j.properties内容:

 
  1. log4j.rootLogger=warn, stdout,A1   
  2.   
  3. #配置输出到控制台   
  4. log4j.appender.stdout=org.apache.log4j.ConsoleAppender   
  5. log4j.appender.stdout.layout=org.apache.log4j.PatternLayout   
  6. log4j.appender.stdout.layout.ConversionPattern=(%F:%L) - %m%n   
  7.   
  8. log4j.appender.A1=org.apache.log4j.DailyRollingFileAppender    
  9. log4j.appender.A1.layout=org.apache.log4j.HTMLLayout   
  10. log4j.appender.A1.File=${webappHome}/logs/${date}_log.html   
  11. log4j.appender.A1.MaxFileSize= 100KB  

   具体log4j.properties的配置方法参见http://hi.baidu.com/276668688/blog/item/e8d2fc1fdd8818c1a786698d.html

4.初始化log4j的配置文件:有两种方法
   方法一:
    a.新建一个初始化类,一般用Servlet或过滤器Log4JInit.java

 
  1. package log4j;    
  2. import java.io.*;    
  3. import javax.servlet.*;    
  4. import javax.servlet.http.*;    
  5. import org.apache.log4j.*;   
  6.   
  7. public class Log4JInit extends HttpServlet {   
  8.    public void init() throws ServletException{   
  9.        String prefix = getServletContext().getRealPath("/");    
  10.        String test = getServletContext().getRealPath("");    
  11.        System.out.println(prefix);    
  12.        System.out.println(test);    
  13.          
  14.        System.setProperty("webappHome", test);   
  15.        String file = getServletConfig().getInitParameter("log4j-config-file");    
  16.        System.out.println(prefix+file);    
  17.        // 从Servlet参数读取log4j的配置文件    
  18.         if (file != null) {    
  19.          PropertyConfigurator.configure(prefix + file);    
  20.           
  21.        }   
  22.    }   
  23. }   

     注意:System.setProperty("webappHome", test);”这行代码要出现在“PropertyConfigurator.configure(prefix + file);”这行代码之前;因为这样才给"webappHome"设置值了,log4j.properties文件中的“log4j.appender.A1.file=${webappHome}/logs/tomcat_log_”中的“${webappHome}”这个环境变量才被赋值了,否则无法输出日志文件;

     b.配置web.xml文件

 
  1. <servlet>    
  2.    <servlet-name>log4jinit</servlet-name>    
  3.    <servlet-class>log4j.Log4JInit</servlet-class>    
  4.    <init-param>    
  5.        <param-name> log4j-config-file </param-name>    
  6.        <param-value>propertieslog4j.properties</param-value>    
  7.    </init-param>    
  8.    <load-on-startup>1</load-on-startup>    
  9. </servlet>  

     注意:上面的load-on-startup应设为1,以便在Web容器启动时即装入该Servlet。log4j.properties文件放在根的properties子目录中,也可以把它放在其它目录中。应该把.properties文件集中存放,这样方便管理。

   方法二、使用Spring已经写好的过滤器
      a.配置web.xml

 
  1. <context-param>  
  2.    <param-name>log4jConfigLocation</param-name>  
  3.    <param-value>/WEB-INF/config/log4j.properties</param-value>  
  4.  </context-param>     
  5.  <context-param>  
  6.    <param-name>log4jRefreshInterval</param-name>  
  7.    <param-value>6000</param-value>  
  8.  </context-param>  
  9.  <listener>  
  10.      <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>  
  11.  </listener>  

5.在webapp中使用log4j
   主要建立一个属性private static Logger logger = Logger.getLogger(Log4jTest.class);

public class Hello extends HttpServlet {
      private static Logger logger = Logger.getLogger(Hello.class);

      @Override
      protected void service(HttpServletRequest request,
      HttpServletResponse response) throws ServletException, IOException {
          System.out.println("Hello world!!");
          logger.debug("log4j加载成功!");
      }

}

6.在具体使用的时候如果触发了异常,就在生成以日期命名的html日志文件tomcat_log_2007-03-05.html了!
  这个日志的格式可以在log4j.properties里面配置.......

====================================================================================================================================================================================================
常用log4j配置

常用log4j配置,一般可以采用两种方式,.properties和.xml,下面举两个简单的例子:

一、 log4j.properties

### 设置org.zblog域对应的级别INFO,DEBUG,WARN,ERROR和输出地A1,A2 ##
log4j.category.org.zblog=ERROR,A1 
log4j.category.org.zblog=INFO,A2 
log4j.appender.A1=org.apache.log4j.ConsoleAppender 
### 设置输出地A1,为ConsoleAppender(控制台) ##
log4j.appender.A1.layout=org.apache.log4j.PatternLayout 
### 设置A1的输出布局格式PatterLayout,(可以灵活地指定布局模式)##
log4j.appender.A1.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} [%c]-[%p] %m%n 
### 配置日志输出的格式##
log4j.appender.A2=org.apache.log4j.RollingFileAppender 
### 设置输出地A2到文件(文件大小到达指定尺寸的时候产生一个新的文件)##
log4j.appender.A2.File=E:/study/log4j/zhuwei.html 
### 文件位置##
log4j.appender.A2.MaxFileSize=500KB 
### 文件大小##
log4j.appender.A2.MaxBackupIndex=1 
log4j.appender.A2.layout=org.apache.log4j.HTMLLayout 
##指定采用html方式输出

二、 log4j.xml

<?xml version="1.0" encoding="GB2312" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="org.zblog.all" class="org.apache.log4j.RollingFileAppender">
<!-- 设置通道ID:org.zblog.all和输出方式:org.apache.log4j.RollingFileAppender -->
   <param name="File" value="E:/study/log4j/all.output.log" /><!-- 设置File参数:日志输出文件名 -->
   <param name="Append" value="false" /><!-- 设置是否在重新启动服务时,在原有日志的基础添加新日志 -->
   <param name="MaxBackupIndex" value="10" /> 
   <layout class="org.apache.log4j.PatternLayout">
       <param name="ConversionPattern" value="%p (%c:%L)- %m%n" /><!-- 设置输出文件项目和格式 -->
   </layout>
</appender>
<appender name="org.zblog.zcw" class="org.apache.log4j.RollingFileAppender">
   <param name="File" value="E:/study/log4j/zhuwei.output.log" />
   <param name="Append" value="true" />
   <param name="MaxFileSize" value="10240" /> <!-- 设置文件大小 -->
   <param name="MaxBackupIndex" value="10" /> 
   <layout class="org.apache.log4j.PatternLayout">
       <param name="ConversionPattern" value="%p (%c:%L)- %m%n" />
   </layout>
</appender>
<logger name="zcw.log"> <!-- 设置域名限制,即zcw.log域及以下的日志均输出到下面对应的通道中 -->
   <level value="debug" /><!-- 设置级别 -->
   <appender-ref ref="org.zblog.zcw" /><!-- 与前面的通道id相对应 -->
</logger>
<root> <!-- 设置接收所有输出的通道 -->
   <appender-ref ref="org.zblog.all" /><!-- 与前面的通道id相对应 -->
</root>
</log4j:configuration>

三、 配置文件加载方法:

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.xml.DOMConfigurator;
public class Log4jApp {
   public static void main(String[] args) {
       DOMConfigurator.configure("E:/study/log4j/log4j.xml");//加载.xml文件
       //PropertyConfigurator.configure("E:/study/log4j/log4j.properties");//加载.properties文件
       Logger log=Logger.getLogger("org.zblog.test");
       log.info("测试");
   }
}

四、 项目使用log4j

在web 应用中,可以将配置文件的加载放在一个单独的servlet中,并在web.xml中配置该servlet在应用启动时候加载。对于在多人项目中,可以给每一个人设置一个输出通道,这样在每个人在构建Logger时,用自己的域名称,让调试信息输出到自己的log文件中。

五、 常用输出格式

# -X号:X信息输出时左对齐;
# %p:日志信息级别
# %d{}:日志信息产生时间
# %c:日志信息所在地(类名)
# %m:产生的日志具体信息
# %n:输出日志信息换行

===============================================================================================

log4j属性含义

1)%r输出程序开始执行之后的微秒数
2)%t输出当前线程的名称
3)%-5p输出消息的层次。
4)%c 输出category的名称
5)-%m及s是日志消息本身,%n是换行符。
  当前在模式字符串中你可以嵌入任何想要输出的字符。
  模式字符串中的模式如下:
%m:消息本身
%p:消息的层次
%r:从程序开始执行到当前日志产生时的时间间隔(微秒)
%c:输出当前日志动作所在的category名称。例如:如果category名称是"a.b.c","%c{2}"将会输出"b.c". {2}意谓着输出“以点分隔开的category名称的后两个组件”,如果 {n}没有,将会输出整个category名称.
%t:输出当前线程的名称
%x:输出和当前线程相关联的NDC(具体解释见下文),尤其用到像java servlets这样的多客户多线程的应用中。
%n:输出平台相关的换行符。
%%:输出一个"%"字符
%d:输出日志产生时候的日期,当然可以对日期的格式进行定制。例如:%d{HH:mm:ss,SSSS}或者是%d{dd MMM yyyy HH:mm:ss,SSSS},如果没有指定后面的格式,将会输出ISO8601的格式。
%l:输出位置信息,相当于%C.%M(%F:%L)的组合。
%C:输出日志消息产生时所在的类名,如果类名是“test.page.Class1”%C{1}表示输出类名"Class1",%C{2}输出"page.Class1",而%C则输出"test.page.Class1"。
%M:输出日志消息产生时的方法名称
%F:输出日志消息产生时所在的文件名称
%L:输出代码中的行号
   可以在%与模式字符之间加上修饰符来控制其最小宽度、最大宽度、和文本的对齐方式。如:
   1)%20c:指定输出category的名称,最小的宽度是20,如果category的名称小于20的话,默认的情况下右对齐。
  2) %-20c:指定输出category的名称,最小的宽度是20,如果category的名称小于20的话,"-"号指定左对齐。
  3) %.30c:指定输出category的名称,最大的宽度是30,如果category的名称大于30的话,就会将左边多出的字符截掉,但小于30的话也不会有空格。
  4)%20.30c:如果category的名称小于20就补空格,并且右对齐,如果其名称长于30字符,就从左边交远销出的字符截掉。
  4)%20.30c:
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
利用spring aop对日志进行管理,还是采用对比的方式进行,

修改前:

偶们的做法是在action里记录日志,注意这个日志是面向用户的日志,姑且称它为业务日志,至于后台日志,则在此文章中暂不考虑,基本是通过log4j打印到后台日志文件中。看下面一段代码: 


   1.  try {   
   2.     employeInfoManageService.saveEmploye(vo, authForm.getLoginName());   
   3.   
   4.     LogVO logVO = new LogVO(Constants.LOG_LEVEL_INFO,   
   5.                 Constants.LOG_TYPE_BACK, "用户:" + authForm.getLoginName()   
   6.                             + "增加员工成功!");   
   7.     logService.saveLog(logVO);   
   8. } catch (Exception e) {   
   9.     log.error(e);   
  10.     LogVO logVO = new LogVO(Constants.LOG_LEVEL_ERROR,   
  11.             Constants.LOG_TYPE_BACK, "用户:" + authForm.getLoginName()   
  12.                             + "增加员工失败!");   
  13.     try {   
  14.         logService.saveLog(logVO);   
  15.     } catch (Exception e1) {   
  16.         log.error(e1);     
  17.     return messageForward("error", "alert.db.exception",      
  18.                     new Object[] {});   }   
  19. }  

这段代码实际上已经将写日志的过程封装起来,开发者只需要传入3个参数:操作者、是前台系统还是后台系统、以及日志的错误等级,其它的如操作者机器IP, 日志时间等信息由系统统一设定,即使是这样,如果一个action里面有多个操作,代码看起来也非常臃肿,而且给开发者增加了工作量,既然有了aop,为 什么不利用一下?看下面改造的代码:

   1.  LogVO logVO = new LogVO(Constants.LOG_LEVEL_INFO,   
   2.                 Constants.LOG_TYPE_BACK, "用户:" + authForm.getLoginName()   
   3.                             + "增加员工");   
   4. try {   
   5.     employeInfoManageService.saveEmploye(vo, authForm.getLoginName(), logVO);   
   6. } catch (Exception e) {   
   7.     log.error(e);   
   8.     return messageForward("error", "alert.db.exception",   
   9.                     new Object[] {});   
  10. }  
既然是应用到aop,当然少不了aop的配置了,看下面的配置代码:
   1.  <aop:config>  
   2.     <aop:advisor pointcut="execution(* *..*Service.*(..))" advice-ref="txAdvice"/>  
     3.     <aop:advisor pointcut="execution(* *..*Service.save*(..)) || execution(* *..*Service.update*(..)) || execution(* *..*Service.delete*(..))" advice-ref="logAfterAdvice"/>  
   4. </aop:config>  
   5.   
   6. <bean id="logAfterAdvice" class="com.fudannet.framework.aop.LogAfterAdvice"/>  
噢,aop:config的第一行是不是很熟悉啊,对,就是我们前面所配置的事务管理,这里,应该很清楚采用统一的aop配置的好处了吧。下面贴出logAfterAdvice的代码:
   1.  public void afterReturning(Object returnObj, Method method, Object[] args,   
   2.             Object targetObj) throws Throwable {   
   3.     if(method.getName().equals("saveLog")) return;   
   4.     for(int i = 0; i < args.length; i++){   
   5.         if(args[i] instanceof LogVO){   
   6.             log.info("开始写入日志......");   
   7.             writeLog((LogVO)args[i]);   
   8.         }   
   9.     }   
  10. }   
  11.   
  12. private void writeLog(LogVO vo){   
  13.     try {   
  14.         vo.setDescription(vo.getDescription() + "成功!");   
  15.         logService.saveLog(vo);   
  16.     } catch (RuntimeException e) {   
  17.         log.error(e);   
  18. }   
  19.   
  20. public void setLogService(LogService logService) {   
  21.     this.logService = logService;   
  22. }  

这段代码应该很清楚了,将logService注入到拦截log的advice里,进行正确操作的日志记录,而afterReturning方法里 的第一行判断是由于logService里的写日志的方法是以save开始的。所以,如果拦截器拦截到此方法,不需要记录日志。

正确的日志记录完,当然如果发生异常,我们需要记录操作的失败日志,当然了,我们也是通过aop来做,但是这次是通过实现exception advice来实现,代码如下: 

   1.  public void afterThrowing(Method method,Object[] args,Object target,Exception e) throws Throwable {   
   2.     if(method.getName().equals("saveLog")) return;   
   3.     for(int i = 0; i < args.length; i++){   
   4.         if(args[i] instanceof LogVO){   
   5.             log.info开始写入日志......");  
   6.             writeLog((LogVO)args[i]);  
   7.         }  
   8.     }  
   9. }  
  10.  
  11. private void writeLog(LogVO vo){  
  12.     try {  
  13.         vo.setDescription(vo.getDescription() + "失败!");   
  14.         logThrowService.saveLog(vo);   
  15.     } catch (RuntimeException e) {   
  16.         log.error(e);   
  17.     }   
  18. }   
  19.   
  20. public void setLogThrowService(LogService logThrowService) {   
  21.     this.logThrowService = logThrowService;   
  22. }  
上面代码已经很好的说明了,如果发生exception的话,日志是怎么记录的,这里要提到的一点的是,异常的处理稍微有一些复杂,就拿本例的代码能看出 来,只要在service层有异常的时候,都会记录失败日志,实际上,很多时候,未必是这样,在某个模块,可能需要定义一种特殊的异常,而一旦这种异常发 生,则需要进入另外一个流程或者做一些特殊的处理,这个时候需要根据具体情况做一些变更,比如在上面代码我们加上:
   1.  public void afterThrowing(Method method,Object[] args,Object target,OrderException e) throws Throwable {   
   2.     log.info("......");   
   3.     //do something   
   4. }  
则如果OrderException被抛出,就会到此方法中执行,而不会去写日志。
--------------------------------------------------------------------------------
其中的封装方式虽然一般,但是还是比较好的解决了问题!对于LogVO类我们可以把他继续扩展下去,比如设定访问用户,IP,seq文等.

Spring AOP与log4j做简单的异常日志处理

1.在网上看了不少例子,下面自己实践了一下。由于系统开发的时候忘记了对异常的日志处理,所以现在考虑加上,经过考虑决定使用spring的aop与log4j来做,这样做的好处就是我不用在每个类里面try{}catch或者抛出异常。因为类已经写了好多好多了。要是一个一个弄工作量是很大的 。 
下面说下简单的实现过程,首先啊,在项目工程中的src目录中加入log4j.properties,内容如下: 

###设置日志级别### 
###这部分是将info信息输出到控制台### 
log4j.rootLogger = info,stdout,F 
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.F = org.apache.log4j.DailyRollingFileAppender 
##输出格式为自定义的HTML## 
log4j.appender.F.layout = com.yale.sys.log.FormatHTMLLayout 
log4j.appender.F.Threshold = ERROR 
log4j.appender.F.Append=true 
##错误文件存放位置## 
log4j.appender.F.File=error.html 
##每天滚动一次文件,即每天产生一个新的文件,文件名字eg:error.html.2012-06-18.html## 
log4j.appender.F.DatePattern='.'yyyy-MM-dd'.html' 

-------------------------------耐心的看下去 ----------------------------------- 
其次呢,看上面红色那部分,因为是要将输出日志信息存储到html文件中,所以重写了下log4j中HTMLLayout类,代码片段: 

Java代码  收藏代码
  1. package com.yale.sys.log;  
  2.   
  3. import java.text.SimpleDateFormat;  
  4. import org.apache.log4j.HTMLLayout;  
  5. import org.apache.log4j.Layout;  
  6. import org.apache.log4j.Level;  
  7. import org.apache.log4j.helpers.Transform;  
  8. import org.apache.log4j.spi.LocationInfo;  
  9. import org.apache.log4j.spi.LoggingEvent;  
  10. /** 
  11.  * log4j输出到html格式重写 
  12.  * @author yale 
  13.  * 
  14.  */  
  15. public class FormatHTMLLayout extends HTMLLayout {     
  16.         
  17.     public FormatHTMLLayout() {     
  18.     }     
  19. [/size]    
  20.     protected final int BUF_SIZE = 256;     
  21.     
  22.     protected final int MAX_CAPACITY = 1024;     
  23.     
  24.     static String TRACE_PREFIX = "<br>&nbsp;&nbsp;&nbsp;&nbsp;";     
  25.     
  26.     // output buffer appended to when format() is invoked     
  27.     private StringBuffer sbuf = new StringBuffer(BUF_SIZE);     
  28.          
  29.     String title="系统错误日志";     
  30.     
  31.     /**   
  32.      * A string constant used in naming the option for setting the the HTML   
  33.      * document title. Current value of this string constant is <b>Title</b>.   
  34.      */    
  35.     public static final String TITLE_OPTION = "Title";     
  36.     
  37.     // Print no location info by default     
  38.     boolean locationInfo = true;     
  39.          
  40.     public String format(LoggingEvent event) {     
  41.         if (sbuf.capacity() > MAX_CAPACITY) {     
  42.             sbuf = new StringBuffer(BUF_SIZE);     
  43.         } else {     
  44.             sbuf.setLength(0);     
  45.         }     
  46.         sbuf.append(Layout.LINE_SEP + "<tr>" + Layout.LINE_SEP);     
  47.              
  48.      
  49.         sbuf.append("<td>");     
  50.         sbuf.append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new java.util.Date()));     
  51.         sbuf.append("</td>" + Layout.LINE_SEP);     
  52.     
  53.    
  54.         sbuf.append("<td title="级别">");     
  55.         if (event.getLevel().equals(Level.FATAL)) {     
  56.             sbuf.append("<font color="#339933">");     
  57.             sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));     
  58.             sbuf.append("</font>");     
  59.         } else if (event.getLevel().isGreaterOrEqual(Level.WARN)) {     
  60.             sbuf.append("<font color="#993300"><strong>");     
  61.             sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));     
  62.             sbuf.append("</strong></font>");     
  63.         } else {     
  64.             sbuf.append("<font color="green">");     
  65.             sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));     
  66.             sbuf.append("</font>");     
  67.         }     
  68.         sbuf.append("</td>" + Layout.LINE_SEP);     
  69.              
  70.   
  71.         if (locationInfo) {     
  72.             LocationInfo locInfo = event.getLocationInformation();     
  73.             sbuf.append("<td title="错误">");   
  74.             sbuf.append("<font color="red">");   
  75.             sbuf.append(Transform.escapeTags(locInfo.getFileName()));    
  76.             sbuf.append(':');    
  77.             sbuf.append(locInfo.getMethodName()).append("()方法中第");  
  78.             sbuf.append(locInfo.getLineNumber()).append("行出现错误");   
  79.             sbuf.append("</font>");   
  80.             sbuf.append("</td>" + Layout.LINE_SEP);    
  81.         }    
  82.             
  83.             
  84.   
  85.             
  86.         sbuf.append("<td title="错误信息">");     
  87.         sbuf.append(Transform.escapeTags(event.getRenderedMessage()));     
  88.         sbuf.append("</td>" + Layout.LINE_SEP);     
  89.         sbuf.append("</tr>" + Layout.LINE_SEP);     
  90.     
  91.         if (event.getNDC() != null) {     
  92.             sbuf.append("<tr><td bgcolor="#EEEEEE" style="font-size : xx-small;" colspan="6" title="Nested Diagnostic Context">");     
  93.             sbuf.append("NDC: " + Transform.escapeTags(event.getNDC()));     
  94.             sbuf.append("</td></tr>" + Layout.LINE_SEP);     
  95.         }     
  96.     
  97.         String[] s = event.getThrowableStrRep();     
  98.         if (s != null) {     
  99.             sbuf.append("<tr><td bgcolor="#993300" style="color:White; font-size : xx-small;" colspan="4">");     
  100.             appendThrowableAsHTML(s, sbuf);     
  101.             sbuf.append("</td></tr>" + Layout.LINE_SEP);     
  102.         }     
  103.         return sbuf.toString();     
  104.     }     
  105.     
  106.     private void appendThrowableAsHTML(String[] s, StringBuffer sbuf) {     
  107.         if (s != null) {     
  108.             int len = s.length;     
  109.             if (len == 0)     
  110.                 return;     
  111.             sbuf.append(Transform.escapeTags(s[0]));     
  112.             sbuf.append(Layout.LINE_SEP);     
  113.             for (int i = 1; i < len; i++) {     
  114.                 sbuf.append(TRACE_PREFIX);     
  115.                 sbuf.append(Transform.escapeTags(s[i]));     
  116.                 sbuf.append(Layout.LINE_SEP);     
  117.             }     
  118.         }     
  119.     }     
  120.     
  121.     /**   
  122.      * Returns appropriate HTML headers.   
  123.      */    
  124.     public String getHeader() {     
  125.         sbuf.append("<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">" + Layout.LINE_SEP);     
  126.         sbuf.append("<html>" + Layout.LINE_SEP);     
  127.         sbuf.append("<head>" + Layout.LINE_SEP);     
  128.         sbuf.append("<title>" + title + "</title>" + Layout.LINE_SEP);     
  129.         sbuf.append("<style type="text/css">" + Layout.LINE_SEP);     
  130.         sbuf.append("<!--" + Layout.LINE_SEP);     
  131.         sbuf.append("body, table {font-family: '宋体',arial,sans-serif; font-size: 12px;}" + Layout.LINE_SEP);     
  132.         sbuf.append("th {background: #336699; color: #FFFFFF; text-align: left;}" + Layout.LINE_SEP);     
  133.         sbuf.append("-->" + Layout.LINE_SEP);     
  134.         sbuf.append("</style>" + Layout.LINE_SEP);     
  135.         sbuf.append("</head>" + Layout.LINE_SEP);     
  136.         sbuf.append("<body bgcolor="#FFFFFF" topmargin="6" leftmargin="6">" + Layout.LINE_SEP);     
  137.         sbuf.append("<table cellspacing="0" cellpadding="4" border="1" bordercolor="#224466" width="100%">" + Layout.LINE_SEP);     
  138.         sbuf.append("<tr>" + Layout.LINE_SEP);     
  139.         sbuf.append("<th>执行时间</th>" + Layout.LINE_SEP);     
  140.         sbuf.append("<th>级别</th>" + Layout.LINE_SEP);     
  141.         if (locationInfo) {     
  142.             sbuf.append("<th>所在行</th>" + Layout.LINE_SEP);     
  143.         }     
  144.         sbuf.append("<th>错误信息</th>" + Layout.LINE_SEP);     
  145.         sbuf.append("</tr>" + Layout.LINE_SEP);     
  146.         sbuf.append("<br></br>" + Layout.LINE_SEP);     
  147.         return sbuf.toString();     
  148.     }     
  149.     
  150. }   


----------------------------耐心点往下看,就要没了 -------------------------------------------------- 
再来就是错误文件error.html的存储位置,想要放在项目的WebRoot下,于是就写了个servlet,代码片段: 

Java代码  收藏代码
  1. package com.yale.sys.log;  
  2. import java.io.FileNotFoundException;  
  3. import java.io.IOException;  
  4. import java.io.InputStream;  
  5. import java.util.Properties;  
  6.   
  7. import javax.servlet.Servlet;  
  8. import javax.servlet.ServletConfig;  
  9. import javax.servlet.ServletException;  
  10. import javax.servlet.http.HttpServlet;  
  11.   
  12.   
  13. import org.apache.log4j.PropertyConfigurator;  
  14.   
  15. /** 
  16.  * 初始化日志错误文件存放的路径 
  17.  */  
  18. public class LogFileSavePathServlet extends HttpServlet {  
  19.     private static final long serialVersionUID = 1L;  
  20.          
  21.     /** 
  22.      * @see HttpServlet#HttpServlet() 
  23.      */  
  24.     public LogFileSavePathServlet() {  
  25.         super();  
  26.         // TODO Auto-generated constructor stub  
  27.     }  
  28.   
  29.     /** 
  30.      * @see Servlet#init(ServletConfig) 
  31.      */  
  32.     public void init() throws ServletException {  
  33.         //获得系统的路径 /WebRoot  
  34.       
  35.         String rootPath = this.getServletContext().getRealPath("/");  
  36.         //获得log4j.properties的输入流  
  37.         InputStream is =this.getClass().getClassLoader().getResourceAsStream("log4j.properties");  
  38.         Properties prop = new Properties();       
  39.         try {  
  40.             prop.load(is);  
  41.         } catch (FileNotFoundException e) {  
  42.             e.printStackTrace();  
  43.         } catch (IOException e) {  
  44.             e.printStackTrace();  
  45.         }   
  46.          //设置日志文件的输出路径     
  47.         prop.setProperty("log4j.appender.F.File",rootPath+prop.getProperty("log4j.appender.F.File"));  
  48.         prop.setProperty("log4j.appender.F.DatePattern",rootPath+prop.getProperty("log4j.appender.F.DatePattern"));  
  49.         //加载配置项     
  50.         PropertyConfigurator.configure(prop);   
  51.         super.init();  
  52.     }  
  53.   
  54.   
  55.   
  56. }  


注意啦,错误文件存储的路径不允许空格上面乱码七糟的,一定要注意哦。 
写完这个servlet,我们不能忘记初始化,您说对不对啊,所以啊,web.xml就像下面这个样子了: 

Java代码  收藏代码
  1. <!DOCTYPE web-app PUBLIC  
  2.  "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"  
  3.  "http://java.sun.com/dtd/web-app_2_3.dtd" >  
  4. <web-app>  
  5. <!-- 日志文件存储路径初始化-->  
  6.     <servlet>  
  7.         <servlet-name>LogFileSavePathServlet</servlet-name>  
  8.         <display-name>LogFileSavePathServlet</display-name>  
  9.         <description></description>  
  10.     <servlet-class>com.peoplespot.sys.log.LogFileSavePathServlet</servlet-class>  
  11.         <load-on-startup>0</load-on-startup>   
  12.     </servlet>  
  13.       <servlet-mapping>  
  14.         <servlet-name>LogFileSavePathServlet</servlet-name>  
  15.         <url-pattern>/LogFileSavePathServlet</url-pattern>  
  16.     </servlet-mapping>  
  17. </web-app>  


--------------------------------下面就开始和spring aop相关啦,看吧,看吧----------------------- 
再一次首先,写一个系统异常日志拦截器类,您看: 

Java代码  收藏代码
  1. package com.yale.sys.log;  
  2.   
  3. import org.apache.log4j.Logger;  
  4. import org.aspectj.lang.ProceedingJoinPoint;  
  5.   
  6. /** 
  7.  * 系统异常日志拦截器 
  8.  * @author yale 
  9.  * 
  10.  */  
  11. public class LogInterceptor {  
  12.       
  13.      static Logger logger = Logger.getLogger(LogInterceptor.class);  
  14.      public Object invoke(ProceedingJoinPoint joinPoint) throws Throwable {    
  15.          StringBuffer sb = new StringBuffer();  
  16.         try{    
  17.             Object result = joinPoint.proceed();    
  18.             return result;    
  19.         }catch(Exception e){    
  20.             sb.append("开始方法:"+joinPoint.getTarget().getClass() + "." + joinPoint.getSignature().getName()+ "()  ");  
  21.             sb.append("错误信息如下:["+e.getMessage()+"]");  
  22.             logger.error(sb.toString());   
  23.         }  
  24.         return "error";//因为用到了strut2,所以出现异常会返回到<result name="error">/erreo.jsp</result>这个页面中,当然啦,你也可以配置成全局的异常返回页。  
  25.     }    
  26. }  


上面这个类,主要用到了aspectj中的ProceedingJoinPoint,支持的是<aop:around />。 
类写完了,但是spring配置文件applicationContext.xml还没有搞啊,所以搞一下: 

Java代码  收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"  
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  5.     xsi:schemaLocation="   
  6.         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd   
  7.         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd   
  8.         http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">  
  9.   
  10. <!-- 配置日志拦截器 -->  
  11.     <bean id="logInterceptor" class="com.yale.sys.log.LogInterceptor"></bean>  
  12.       
  13.     <aop:config proxy-target-class="true">  
  14.         <aop:aspect id="logAspectSYS" ref="logInterceptor">  
  15.             <aop:around method="invoke" pointcut="execution(public * com.yale.live.action..*.*(..))" />  
  16.         </aop:aspect>  
  17.             <aop:aspect id="logAspectDNA" ref="logInterceptor">  
  18.             <aop:around method="invoke" pointcut="execution(public * com.yale.sys.action..*.*(..))" />  
  19.         </aop:aspect>  
  20.     </aop:config>  
  21. </beans>  


小插曲:看见<aop:config>节点中proxy-target-class="true"这个属性了吧,当我不加的时候,启动项目,访问action代码,就比如是LoginAction中的login()方法,不幸的是他报错了,类似于 
java.lang.NoSuchMethodException: $Proxy54.login(),可是回去一看,有写过这个login方法啊, $Proxy54又是怎么回事呢?因为你加入aop功能了,可是spring是这么干的,默认啊实现的是接口注入,关联的实现类。这里实现注入类,所以出现了异常。要怎么解决呢,于是就要加上proxy-target-class="true"属性,接下来启动项目吧,你会发现不幸的事情又发生了,又报错了: 
org.springframework.aop.framework.AopConfigException: Cannot proxy target class because CGLIB2 is not available. Add CGLIB to the class path or specify proxy interfaces. 
提示的很明显,少jar包了,所以就加吧,但是加jar的时候也要注意了: 
需要导入的jar包是cglib-nodep-2.1_3.jar(这里面整合了asm)或者(asm-2.2.3.jar和cglib-2.2.jar 。)因为cglib需要asm的支持。 
到此完成。 
启动项目开始运行吧,模拟了下一个异常,输出到html最终这样啦: 


 
原文地址:https://www.cnblogs.com/wnlja/p/3912821.html