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> ";
// 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
分享到:
相关推荐
NULL 博文链接:https://miaoxianjie.iteye.com/blog/2067308
ssh+aop+log4j+日志拦截器+注解
spring boot aop 统一处理日志 demo spring boot aop 统一处理日志 demo
此工程为使用eclipse创建java project,使用jdk1.8,项目中包含完整的代码和jar包,导入eclipse即可运行
Spring MVC AOP通过自定义注解方式拦截Controller等实现日志管理, springMVC里做添加AOP拦截,用于捕获异常。
基于Log4j+SpringAOP+Annotation的可注解日志切面组件 使用方式 @Log(logAfter = true, logBefore = true) public returntype methodName(params) 测试类com.liam.aop.aspect.test.AopLogAnnotationTest 测试输出 ...
Spring Boot项目中使用Logback日志与使用AOP拦截请求日志信息
AopLogAopLog是基于SpringAop和ThreadLocal实现的一个对请求方法埋点记录与处理的日志工具包。设计目的和场景:使用Spring Aop拦截程序,基本上都是同一个小异,不想日后每个项目都柏林都写一份这样的Aop拦截处理...
在Spring1.2或之前的版本中,实现AOP的传统方式就是通过实现Spring的AOP API来定义Advice,并设置代理对象。Spring根据Adivce加入到业务流程的时机的不同,提供了四种不同的Advice:Before Advice、After Advice、...
项目日志记录是项目开发、运营必不可少的内容,有了它可以对系统有整体的把控,出现任何问题都有踪迹可寻。下面这篇文章主要给大家介绍了关于Spring MVC项目中log4J和AOP使用的相关资料,需要的朋友可以参考下。
自定义日志输出,加aop切面Controller,使用DRUID访问mysql,spring mvc基本框架搭建,适合初学者,页面适用IE6
功能:实现AOP中异常日志管理的类
日志记录:以JSON格式输出日志,通过log4j配置日志文件输出方式。 日志查询:提供servlet加载日志文件,前台JSON处理查询对照。 详细作用说明参考:http://jingyan.baidu.com/edit/content?type=draft&did=3
2.1log4j-1.2.17.jar commons-logging相当于一个日志接口,log4j相当于该接口的实现,如果不添加log4j包也可以,因为commons-logging也有一个简单的实现会自动使用。 3. 测试类包 3.1spring-test-4.1.3.RELEASE....
主要介绍了Spring Boot2集成AOPLog来记录接口访问日志,日志是一个Web项目中必不可少的部分,借助它我们可以做许多事情,比如问题排查、访问统计、监控告警等,需要的朋友可以参考下
--演示了如何在Spring Boot里面使用日志配置,以及logback,log4j2等日志的使用 23 Spring Boot 监控和度量47:09 --Spring Boot内置的监控点、自定义的监控状况检查、自定义度量统计,输出等等 24 Spring Boot ...
log4j-1.2.17.jar spring-aop-5.2.6.RELEASE.jar spring-aspects-5.2.6.RELEASE.jar spring-beans-5.2.6.RELEASE.jar spring-context-5.2.6.RELEASE.jar spring-core-5.2.6.RELEASE.jar spring-expression-5.2.6....
Spring AOP! 弹簧速度自由标记
AutoLogging 监控日志框架一个非常强大的监控日志输出框架,主要功能包含方法监控日志输出应用内调用链路追踪可以通过SpringAOP动态字节码运行时注入两种方式引入,只要一个注解即可开启所有功能,而且具有强大的可...
功能包括:功能日志记录(访问、参数、异常、返回结果集)、数据日志记录、日志查询... 日志记录:以JSON格式输出日志,通过log4j配置日志文件输出方式。 日志查询:提供servlet加载日志文件,前台JSON处理查询对照。