`

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类,代码片段:
package com.yale.sys.log;

import java.text.SimpleDateFormat;
import org.apache.log4j.HTMLLayout;
import org.apache.log4j.Layout;
import org.apache.log4j.Level;
import org.apache.log4j.helpers.Transform;
import org.apache.log4j.spi.LocationInfo;
import org.apache.log4j.spi.LoggingEvent;
/**
 * log4j输出到html格式重写
 * @author yale
 *
 */
public class FormatHTMLLayout extends HTMLLayout {   
	  
    public FormatHTMLLayout() {   
    }   
[/size]  
    protected final int BUF_SIZE = 256;   
  
    protected final int MAX_CAPACITY = 1024;   
  
    static String TRACE_PREFIX = "<br>&nbsp;&nbsp;&nbsp;&nbsp;";   
  
    // output buffer appended to when format() is invoked   
    private StringBuffer sbuf = new StringBuffer(BUF_SIZE);   
       
    String title="系统错误日志";   
  
    /**  
     * A string constant used in naming the option for setting the the HTML  
     * document title. Current value of this string constant is <b>Title</b>.  
     */  
    public static final String TITLE_OPTION = "Title";   
  
    // Print no location info by default   
    boolean locationInfo = true;   
       
    public String format(LoggingEvent event) {   
        if (sbuf.capacity() > MAX_CAPACITY) {   
            sbuf = new StringBuffer(BUF_SIZE);   
        } else {   
            sbuf.setLength(0);   
        }   
        sbuf.append(Layout.LINE_SEP + "<tr>" + Layout.LINE_SEP);   
           
   
        sbuf.append("<td>");   
        sbuf.append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new java.util.Date()));   
        sbuf.append("</td>" + Layout.LINE_SEP);   
  
 
        sbuf.append("<td title=\"级别\">");   
        if (event.getLevel().equals(Level.FATAL)) {   
            sbuf.append("<font color=\"#339933\">");   
            sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));   
            sbuf.append("</font>");   
        } else if (event.getLevel().isGreaterOrEqual(Level.WARN)) {   
            sbuf.append("<font color=\"#993300\"><strong>");   
            sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));   
            sbuf.append("</strong></font>");   
        } else {   
            sbuf.append("<font color=\"green\">");   
            sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));   
            sbuf.append("</font>");   
        }   
        sbuf.append("</td>" + Layout.LINE_SEP);   
           

        if (locationInfo) {   
            LocationInfo locInfo = event.getLocationInformation();   
            sbuf.append("<td title=\"错误\">"); 
            sbuf.append("<font color=\"red\">"); 
            sbuf.append(Transform.escapeTags(locInfo.getFileName()));  
            sbuf.append(':');  
            sbuf.append(locInfo.getMethodName()).append("()方法中第");
            sbuf.append(locInfo.getLineNumber()).append("行出现错误"); 
            sbuf.append("</font>"); 
            sbuf.append("</td>" + Layout.LINE_SEP);  
        }  
          
          

          
        sbuf.append("<td title=\"错误信息\">");   
        sbuf.append(Transform.escapeTags(event.getRenderedMessage()));   
        sbuf.append("</td>" + Layout.LINE_SEP);   
        sbuf.append("</tr>" + Layout.LINE_SEP);   
  
        if (event.getNDC() != null) {   
            sbuf.append("<tr><td bgcolor=\"#EEEEEE\" style=\"font-size : xx-small;\" colspan=\"6\" title=\"Nested Diagnostic Context\">");   
            sbuf.append("NDC: " + Transform.escapeTags(event.getNDC()));   
            sbuf.append("</td></tr>" + Layout.LINE_SEP);   
        }   
  
        String[] s = event.getThrowableStrRep();   
        if (s != null) {   
            sbuf.append("<tr><td bgcolor=\"#993300\" style=\"color:White; font-size : xx-small;\" colspan=\"4\">");   
            appendThrowableAsHTML(s, sbuf);   
            sbuf.append("</td></tr>" + Layout.LINE_SEP);   
        }   
        return sbuf.toString();   
    }   
  
    private void appendThrowableAsHTML(String[] s, StringBuffer sbuf) {   
        if (s != null) {   
            int len = s.length;   
            if (len == 0)   
                return;   
            sbuf.append(Transform.escapeTags(s[0]));   
            sbuf.append(Layout.LINE_SEP);   
            for (int i = 1; i < len; i++) {   
                sbuf.append(TRACE_PREFIX);   
                sbuf.append(Transform.escapeTags(s[i]));   
                sbuf.append(Layout.LINE_SEP);   
            }   
        }   
    }   
  
    /**  
     * Returns appropriate HTML headers.  
     */  
    public String getHeader() {   
        sbuf.append("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">" + Layout.LINE_SEP);   
        sbuf.append("<html>" + Layout.LINE_SEP);   
        sbuf.append("<head>" + Layout.LINE_SEP);   
        sbuf.append("<title>" + title + "</title>" + Layout.LINE_SEP);   
        sbuf.append("<style type=\"text/css\">" + Layout.LINE_SEP);   
        sbuf.append("<!--" + Layout.LINE_SEP);   
        sbuf.append("body, table {font-family: '宋体',arial,sans-serif; font-size: 12px;}" + Layout.LINE_SEP);   
        sbuf.append("th {background: #336699; color: #FFFFFF; text-align: left;}" + Layout.LINE_SEP);   
        sbuf.append("-->" + Layout.LINE_SEP);   
        sbuf.append("</style>" + Layout.LINE_SEP);   
        sbuf.append("</head>" + Layout.LINE_SEP);   
        sbuf.append("<body bgcolor=\"#FFFFFF\" topmargin=\"6\" leftmargin=\"6\">" + Layout.LINE_SEP);   
        sbuf.append("<table cellspacing=\"0\" cellpadding=\"4\" border=\"1\" bordercolor=\"#224466\" width=\"100%\">" + Layout.LINE_SEP);   
        sbuf.append("<tr>" + Layout.LINE_SEP);   
        sbuf.append("<th>执行时间</th>" + Layout.LINE_SEP);   
        sbuf.append("<th>级别</th>" + Layout.LINE_SEP);   
        if (locationInfo) {   
            sbuf.append("<th>所在行</th>" + Layout.LINE_SEP);   
        }   
        sbuf.append("<th>错误信息</th>" + Layout.LINE_SEP);   
        sbuf.append("</tr>" + Layout.LINE_SEP);   
        sbuf.append("<br></br>" + Layout.LINE_SEP);   
        return sbuf.toString();   
    }   
  
} 


----------------------------耐心点往下看,就要没了 --------------------------------------------------
再来就是错误文件error.html的存储位置,想要放在项目的WebRoot下,于是就写了个servlet,代码片段:
package com.yale.sys.log;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;


import org.apache.log4j.PropertyConfigurator;

/**
 * 初始化日志错误文件存放的路径
 */
public class LogFileSavePathServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public LogFileSavePathServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see Servlet#init(ServletConfig)
	 */
	public void init() throws ServletException {
		//获得系统的路径 /WebRoot
	
	 	String rootPath = this.getServletContext().getRealPath("/");
	 	//获得log4j.properties的输入流
	 	InputStream is =this.getClass().getClassLoader().getResourceAsStream("log4j.properties");
        Properties prop = new Properties();     
        try {
			prop.load(is);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} 
		 //设置日志文件的输出路径   
		prop.setProperty("log4j.appender.F.File",rootPath+prop.getProperty("log4j.appender.F.File"));
		prop.setProperty("log4j.appender.F.DatePattern",rootPath+prop.getProperty("log4j.appender.F.DatePattern"));
		//加载配置项   
        PropertyConfigurator.configure(prop); 
        super.init();
	}



}


注意啦,错误文件存储的路径不允许空格上面乱码七糟的,一定要注意哦。
写完这个servlet,我们不能忘记初始化,您说对不对啊,所以啊,web.xml就像下面这个样子了:
<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<!-- 日志文件存储路径初始化-->
    <servlet>
    	<servlet-name>LogFileSavePathServlet</servlet-name>
    	<display-name>LogFileSavePathServlet</display-name>
    	<description></description>
    <servlet-class>com.peoplespot.sys.log.LogFileSavePathServlet</servlet-class>
    	<load-on-startup>0</load-on-startup> 
    </servlet>
      <servlet-mapping>
    	<servlet-name>LogFileSavePathServlet</servlet-name>
    	<url-pattern>/LogFileSavePathServlet</url-pattern>
    </servlet-mapping>
</web-app>

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

import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;

/**
 * 系统异常日志拦截器
 * @author yale
 *
 */
public class LogInterceptor {
	
	 static Logger logger = Logger.getLogger(LogInterceptor.class);
	 public Object invoke(ProceedingJoinPoint joinPoint) throws Throwable {  
    	 StringBuffer sb = new StringBuffer();
        try{  
            Object result = joinPoint.proceed();  
            return result;  
        }catch(Exception e){  
        	sb.append("开始方法:"+joinPoint.getTarget().getClass() + "." + joinPoint.getSignature().getName()+ "()  ");
        	sb.append("错误信息如下:["+e.getMessage()+"]");
        	logger.error(sb.toString()); 
        }
        return "error";//因为用到了strut2,所以出现异常会返回到<result name="error">/erreo.jsp</result>这个页面中,当然啦,你也可以配置成全局的异常返回页。
    }  
}

上面这个类,主要用到了aspectj中的ProceedingJoinPoint,支持的是<aop:around />。
类写完了,但是spring配置文件applicationContext.xml还没有搞啊,所以搞一下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation=" 
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd 
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd 
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">

<!-- 配置日志拦截器 -->
	<bean id="logInterceptor" class="com.yale.sys.log.LogInterceptor"></bean>
	
	<aop:config proxy-target-class="true">
		<aop:aspect id="logAspectSYS" ref="logInterceptor">
			<aop:around method="invoke" pointcut="execution(public * com.yale.live.action..*.*(..))" />
		</aop:aspect>
			<aop:aspect id="logAspectDNA" ref="logInterceptor">
			<aop:around method="invoke" pointcut="execution(public * com.yale.sys.action..*.*(..))" />
		</aop:aspect>
	</aop:config>
</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最终这样啦:


  • 大小: 109 KB
分享到:
评论
4 楼 ll_wang11 2015-01-20  
               
3 楼 记忆无泪 2012-09-25  
楼主是不是把代码修改下呢?因为你那个输出的错误的代码行数一直是错的。

StackTraceElement ste = e.getStackTrace()[0];
        	sb.append("开始方法:"+joinPoint.getTarget().getClass() + "." + joinPoint.getSignature().getName()+ "("+ste.getFileName()+":"+ste.getLineNumber()+") ");
        	sb.append("错误信息如下:["+e.getMessage()+"]");
2 楼 liguocai2009 2012-07-03  
看半天不知道aop发挥了什么作用?
在interceptor捕捉excpetion调用log.error(msg,e)不就行了吗?
1 楼 虚弱的java 2012-06-19  
启动项目开始运行吧,模拟了下一个异常,输出到html最终这样啦

相关推荐

    Spring Aop+Log4j 动态日志

    在"AopLog4jLearn"这个压缩包中,可能包含了关于这个主题的示例代码、配置文件和其他相关资料。读者可以通过学习这些材料,更深入地理解Spring AOP和Log4j的结合使用,以及如何在实际项目中应用动态日志功能。

    spring简单注解+log4j记录日志

    综上所述,"spring简单注解+log4j记录日志"这个主题涵盖了Spring框架中的注解使用、Log4j日志系统以及AOP的应用。通过学习这些内容,初学者可以更好地理解和实践Spring框架,同时提高代码的可维护性和调试效率。在...

    ssh+aop+log4j+日志拦截器+注解

    标题中的"ssh+aop+log4j+日志拦截器+注解"涉及到的是Java Web开发中的几个核心组件和技术,这些技术在构建大型、分布式的企业级应用时常常被使用。下面将详细介绍这些知识点: 1. SSH (Spring, Struts, Hibernate)...

    springmvc中使用log4j及aop记录日志的例子

    在这个例子中,我们将讨论如何将Log4j与Spring MVC和AOP结合,实现方法调用前后的日志打印。 首先,让我们了解Log4j的基本配置。Log4j的配置文件通常是`log4j.properties`或`log4j.xml`,定义了日志的级别(如DEBUG...

    简单spring aop 例子

    Spring AOP(面向切面编程)是Spring框架的重要组成部分,它提供了一种模块化和声明式的方式来处理系统中的交叉关注点问题,如日志、事务管理、安全性等。本示例将简要介绍如何在Spring应用中实现AOP,通过实际的...

    spring AOP 切面日志 分层打日志

    2. **日志框架集成**: 使用如Log4j、Logback等日志框架,它们提供更丰富的功能和更好的性能。 3. **日志归档和检索**: 考虑日志文件的大小和存储,定期归档,并提供日志检索工具。 4. **异常处理**: 记录异常堆栈...

    spring框架和log4j日志用到的jar包

    使用Spring时,开发者还需要注意与其他Java库的兼容性,例如JDBC驱动、ORM框架(如Hibernate、MyBatis)的jar包,以及用于日志记录的log4j.jar、log4j-api.jar和log4j-core.jar。在实际项目中,这些jar包通常会被...

    spring aop 切面添加日志

    项目中包含的jar包可能是Spring框架和其他依赖,如log4j或slf4j,这些库提供了日志记录功能。你可以通过配置这些库的日志级别(如DEBUG、INFO、WARN等)来控制日志输出的详细程度。 最后,确保在Eclipse中正确导入...

    Spring MVC 框架 整合log4j

    3. **在Spring MVC中使用Log4j**:在Spring MVC的Controller或其他需要记录日志的类中,引入`org.apache.log4j.Logger`,并创建一个实例。例如: ```java import org.apache.log4j.Logger; public class ...

    Spring Aop四个依赖的Jar包

    这个组件使得Spring AOP能够与未修改的第三方库无缝集成,因为Spring AOP可以利用AspectJ Weaver来处理那些不支持代理的对象。 3. **cglib-nodep-2.1_3.jar**:CGLIB(Code Generation Library)是一个高性能的代码...

    Spring Mvc AOP通过注解方式拦截controller等实现日志管理

    Spring MVC AOP日志管理通常与日志框架(如Log4j、Logback或Java内置的java.util.logging)集成。以下以Log4j为例: 1. 引入依赖:在项目pom.xml中添加Log4j的依赖。 2. 配置Log4j:创建log4j.properties或log4j....

    spring整合log4j

    Spring提供了与各种日志框架的集成,包括Log4j,使得日志配置更加方便。 整合Spring和Log4j,我们需要完成以下步骤: 1. **引入依赖**:在项目的Maven或Gradle构建文件中添加Log4j的依赖库。对于Maven,可以在`pom...

    springmvc log4j2 logback 注解 jackson 日志脱敏实现源码

    `Logback`和`Log4j`都是广泛使用的日志框架,它们允许自定义日志格式和处理策略。 2. **SpringMVC返回报文脱敏**:`SpringMVC`是Spring框架的一个模块,主要用于构建Web应用。在响应报文时,如果包含了敏感信息(如...

    spring aop实现日志功能

    - 在通知方法中,你可以使用标准的日志库如log4j、logback或Java内置的日志API(java.util.logging.Logger)来记录日志。通常,日志应包含方法名、参数、执行时间、返回值(如果适用)以及任何异常信息。 5. **...

    Spring AOP简单demo

    6. **错误处理**:统一处理异常,提供友好的错误信息。 通过学习和实践Spring AOP,开发者可以更高效地组织代码,将关注点分离,提升代码的可读性和可维护性。在Spring AOPD1这个压缩包中,可能包含了创建和运行...

    spring boot aop 统一处理日志

    为了使日志更易于管理和分析,我们可以使用日志框架,如Logback或Log4j2,将这些输出定向到日志文件。Spring Boot默认集成了Logback,只需在配置文件(application.properties或application.yml)中设置相应的日志...

    springAop与spring定时器

    Spring AOP(面向切面编程)是Spring框架中的一个重要组件,它允许我们在不修改源代码的情况下,通过在程序运行时动态地将代码插入到方法调用中,来实现跨切面的关注点,如日志记录、性能监控、事务管理等。而Spring...

    spring.net结合三层AOP异常日志记录功能

    在异常情况下,可以定义一个切面来捕获并处理异常,同时记录日志。 4. **异常日志记录**:日志记录是系统故障排查的重要手段。我们可以创建一个自定义的日志类,实现IAdvice接口,这样Spring.NET就能在发生异常时...

    Spring AOP的简单实现

    在这个场景中,我们将使用Spring AOP来实现一个日志记录的功能,以追踪系统中各个方法的调用情况,包括访问时间以及传递的参数。下面将详细阐述如何实现这一目标。 首先,我们需要了解AOP的基本概念。AOP的核心是切...

Global site tag (gtag.js) - Google Analytics