springMVC,aop管理log4j,把当前session信息和错误信息打印到日志

((((其实还是不太理解aop的正真意义但是这样可以实现想要的了,我的感觉是执行一个方法时首先通过filter( 这个fiter可以不配置,之所以要他是因为在aop切入的方法session消失了,我们要保存是谁在操作就需要他) > aop管理的log4j类,>log4j 来搞定日志的处理))))

记录一下学习路径,终于搞通了关于spring aop管理log4j和有关session的问题,目的是 当某个用户进行什么操作发生了什么异常,记录到日志以备查找错误进行修改,参考文档:http://blog.csdn.net/sorrow199117/article/details/8848505 这位大神写的我从头一直做到尾,但是就是获取不到session,如果没有用户信息记录不了用户就没什么意义了,继续调试,我靠 ,最后发现是缓存的问题,清理了服务器问题解决,借用大神的一句话:AOP配置文件会去检查你是否对此方法配置了日志切面,如果配置了,这儿是后向切入,他会在执行此方法之后执行切入类的一个方法(AOP配置此方法),切入类得到了此方法的完整路径名称,他会到一个配置文件中去读取方法描述,然后用log4j记录此描述信息

1. spring的配置文件 XXX.xml ,aop配置代码段

        <pre name="code" class="html"><aop:config>
		<aop:pointcut id="serviceOperation" expression="execution (* com.esh.eatsong.customServer.*.service.impl.*.*(..))"/>
		<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation"/>
	</aop:config>
	
	<!--配置log对象-->
	<bean id="logger" class="org.slf4j.LoggerFactory" factory-method="getLogger">
		<constructor-arg type="java.lang.String" value=""></constructor-arg>
	</bean>
	
	<bean id="action_log" class="org.slf4j.LoggerFactory" factory-method="getLogger">
		<constructor-arg type="java.lang.String" value="action_log"></constructor-arg>
	</bean>	
	<bean id="service_log" class="org.slf4j.LoggerFactory" factory-method="getLogger">
		<constructor-arg type="java.lang.String" value="service_log"></constructor-arg>
	</bean>	
	<bean id="dao_log" class="org.slf4j.LoggerFactory" factory-method="getLogger">
		<constructor-arg type="java.lang.String" value="dao_log"></constructor-arg>
	</bean>	
	<bean id="job_log" class="org.slf4j.LoggerFactory" factory-method="getLogger">
		<constructor-arg type="java.lang.String" value="job_log"></constructor-arg>
	</bean>
	

 

 2.下面是web.xml配置log4j 的主要部分 当启动项目时加载 

我把log4j.properties配置文件放在源文件夹下logs/XXX 目录下编译之后的路径是WEB-INF/classes/logs/XXXX

  <!--*******log4j日志信息的配置-->
	<context-param>
	    <param-name>log4jConfigLocation</param-name>
	    <param-value>classpath:logs/log4j.properties</param-value>
	</context-param>
	<!--Spring默认刷新Log4j配置文件的间隔,单位为millisecond,可以不设置 -->  
    <context-param>  
        <param-name>log4jRefreshInterval</param-name>  
        <param-value>60000</param-value>  
    </context-param> 
<!-- Filter : GetUserFilter 他的作用是从SESSION中获取当前登录用户的信息,
    	在Log4j配置文件中用到了,比如%X{name}是获取用户姓名,但是要在此Filter中先设置name属性。
    	GetUserFilter是关键所在,因为等一下用AOP切入的方法已经得不到用户信息了,就要靠他了 -->
	<filter>  
		<filter-name>GetUserFilter</filter-name>  
		<filter-class>com.esh.eatsong.framework.util.GetUserFilter</filter-class>  
		   </filter>  
		   <filter-mapping>  
		<filter-name>GetUserFilter</filter-name>  
		<url-pattern>/*</url-pattern>  
	</filter-mapping> 
log4j.properties 配置文件  这个文件但是搞了半天才明白这些类似与C 的代码是什么意思不知道的可以

参考:http://zc2690790.blog.163.com/blog/static/127891478200981445953120/

# root logger 
log4j.rootLogger=error, stdout, file ,filter
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,[%-5p],%x,%c,%m%n

log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=/home/shareupload/zhxy/logs/platform/system.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d,[%-5p],%x,%c,%m%n
log4j.appender.file.MaxFileSize=10480KB
log4j.appender.file.MaxBackupIndex=50 


# hibernate log
log4j.logger.org.hibernate=error, hibernate
#log4j.appender.hibernate=org.apache.log4j.DailyRollingFileAppender
log4j.appender.hibernate=org.apache.log4j.RollingFileAppender
log4j.appender.hibernate.File=/home/shareupload/zhxy/logs/platform/hibernate.log
log4j.appender.hibernate.DatePattern='.'yyyy-MM-dd
log4j.appender.hibernate.layout=org.apache.log4j.PatternLayout
log4j.appender.hibernate.layout.ConversionPattern=%d,[%-5p],%x,%c,%m%n
log4j.appender.hibernate.MaxFileSize=10480KB
log4j.appender.hibernate.MaxBackupIndex=50


# filter log   这里 %X{key} 在filter里用MDC.put("cus_id", "cus_id:"+customer.getId());给key赋值
log4j.appender.filter=org.apache.log4j.RollingFileAppender
log4j.appender.filter.File=/home/shareupload/zhxy/logs/platform/filter.log
log4j.appender.filter.DatePattern='.'yyyy-MM-dd
log4j.appender.filter.layout=org.apache.log4j.PatternLayout
log4j.appender.filter.layout.ConversionPattern=%d,[%-5p],%X{cus_id},%X{cus_tel},%X{emp_id},%X{emp_name},%c,[%l], %m%n 
log4j.appender.filter.MaxFileSize=10480KB
log4j.appender.filter.MaxBackupIndex=50

过滤器 ,用这个filter获得我们登陆时的session信息并且把用户通过%X{cus_id}形式进行打印到日志

package com.esh.eatsong.framework.util;

/**  
 * 文件名: GetUserFilter.java  
 * 描述:(得到SESSION中的用户)  
 */

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.log4j.MDC;

import com.esh.eatsong.customServer.customer.pojo.Customer;
import com.esh.eatsong.customServer.employee.pojo.Employee;

public class GetUserFilter  implements Filter {

	// 定义默认用户姓名
	private final static String DEFAULT_USER = "guest";
	// 定义默认用户tel
	private final static String DEFAULT_TEL = "guestTel";

	public void destroy() {
	}

	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		HttpServletRequest req = (HttpServletRequest) request;
		HttpSession session = req.getSession();
		if (session == null) {
			MDC.put("cus_id", (int) (Math.random() * 1000));
			MDC.put("cus_tel", DEFAULT_TEL);
			MDC.put("emp_id", (int) (Math.random() * 1000));
			MDC.put("emp_name", DEFAULT_USER);
		} else {
			Employee employee = (Employee) session.getAttribute("employee");
			Customer customer = (Customer) session.getAttribute("customer");
			if (customer == null) {
				MDC.put("cus_id", (int) (Math.random() * 1000));
				MDC.put("cus_tel", DEFAULT_TEL);
			} else {
				MDC.put("cus_id", "cus_id:"+customer.getId());
				MDC.put("cus_tel",customer.getTelphone());
			}
			if (employee==null) {
				MDC.put("emp_id", (int) (Math.random() * 1000));
				MDC.put("emp_name", DEFAULT_USER);
			} else {
				MDC.put("emp_id", "emp_id:"+employee.getId());
				MDC.put("emp_name",employee.getName());
			}
			
		}

		chain.doFilter(request, response);
	}

	public void init(FilterConfig Config) throws ServletException {

	}
}

制造一个error异常

package com.esh.framework.util;

import java.lang.reflect.Method;

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

/**
 * 基于注解的AOP日志示例
 * @author 
 */
@Component
@Aspect
public class AopLog {
	

	 /** 
	     * 必须为final String类型的,注解里要使用的变量只能是静态常量类型的 
	  */  
	private static final String EDP = "execution (* com.esh.eatsong.customServer.*.*.impl.*.*(..))";
	private static final Logger logger = Logger.getLogger(Log4jAspect.class);
	private static final String DOT = ".";//点号
	private static final String COMMA = ",";//逗号
	String strLog = null ;  

	 /** 
     * 前置通知:在某连接点之前执行的通知,但这个通知不能阻止连接点前的执行 
     * @param jp 连接点:程序执行过程中的某一行为,例如,AServiceImpl.barA()的调用或者抛出的异常行为 
     */  
    public void doBefore(JoinPoint jp) {  
        strLog = "log Begining method: "  
                + jp.getTarget().getClass().getName() + "."  
                + jp.getSignature().getName();  
        logger.warn(strLog);  
    }  
 
 
    /** 
     * 抛出异常后通知 : 在方法抛出异常退出时执行的通知。 
     * @param jp 连接点:程序执行过程中的某一行为,例如,AServiceImpl.barA()的调用或者抛出的异常行为 
     */  
    public void doAfter(JoinPoint jp) {  
        strLog ="doAfter:log Ending method: "  
                + jp.getTarget().getClass().getName() + "."  
                + jp.getSignature().getName();   
        logger.warn(strLog);  
    }  
	
    /** 
     * 环绕通知:包围一个连接点的通知,可以在方法的调用前后完成自定义的行为,也可以选择不执行 
     * 类似Web中Servlet规范中的Filter的doFilter方法。 
     * @param pjp 当前进程中的连接点 
     * @return 
     * @throws Throwable 
     */ 
    @Around(EDP)
	public Object rround(ProceedingJoinPoint joinPoint) throws Throwable {
	    StringBuilder sb = new StringBuilder();
	    Object[] paramValues = joinPoint.getArgs();//获取参数值
	    String[] paramNames = new String[paramValues.length];
        Class<? extends Object> invokeClass = joinPoint.getTarget().getClass();
        String signatureName = joinPoint.getSignature().getName();
	    Method methods[] = invokeClass.getMethods();
	    for (Method method : methods) {
	    	if(method.getName().equals(signatureName)) {
                String paramCollection ="";
                AOPLog4jAnnotation log4jAnnotation = method.getAnnotation(AOPLog4jAnnotation.class);
                if(log4jAnnotation!=null){
                	paramCollection=log4jAnnotation.paramCollection();//获取注解值
                	String[] names = paramCollection.split(COMMA);
    				System.arraycopy(names, 0, paramNames, 0, names.length);
                }else{
                	;
                }
				
			}
		}
	    
	    for (int i = 0; i < paramValues.length; i++) {
	    	sb.append(paramNames[i] + "=" + paramValues[i] + COMMA);
	    }
        //入参日志
	    if(sb.length()!=0){
	    	logger.info(invokeClass  + DOT + signatureName + ",remote input:" 
                    + sb.toString().substring(0, sb.length() - 1));	
	    }
		   Object result = joinPoint.proceed();
           //出参日志
		   logger.info(invokeClass  + DOT + signatureName 
                   + ",remote output:" + result);
           return result;

	
	}
	//方法运行出现异常时调用
	@AfterThrowing(pointcut = EDP,throwing = "ex")
	public void afterThrowing(JoinPoint jp, Exception ex){
		strLog ="afterThrowing:log Ending method: " + jp.getTarget().getClass().getName() + DOT + jp.getSignature().getName();   
		logger.error(strLog+"["+ex+"]");
	}
}



web项目日志输出文件在服务器根目录下 然后跟路径/X/X/XX/filter.log

高度关注filter.log 这里存放了session信息




  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值