过滤器实现用户访问记录日志记录

需求:

1.记录用户请求记录,需要记录请求的参数,在异常情况下可以复现异常。

2.记录每个请求的响应记录。

实现:

记录请求日志

1.使用log4j输出记录到单独日志文件中,配置log4j

#配置logger和日志输出等级
log4j.logger.com.jsz.peini.interceptor.AccessLogFilter= INFO,accessLog
#配置不继承父类appender 它是 子Logger 是否继承 父Logger 的 输出源(appender) 的标志位。具体说,默认情况下子#Logger会继承父Logger的appender,也就是说子Logger会在父Logger的appender里输出。若是additivity设为false,则子#Logger只会在自己的appender里输出,而不会在父Logger的appender里输出。
log4j.additivity.com.jsz.peini.interceptor.AccessLogFilter=false
#配置按天滚动日志文件
log4j.appender.accessLog=org.apache.log4j.DailyRollingFileAppender
#日志文件位置
log4j.appender.accessLog.File=d:/peinilog/peini20access.log
#文件名
log4j.appender.accessLog.DatePattern=yyyy-MM-dd'.log'
log4j.appender.accessLog.layout=org.apache.log4j.PatternLayout
log4j.appender.accessLog.layout.ConversionPattern=%-d{yyyy-MM-dd HH\:mm\:ss} - %m%n
log4j.additivity.accessLog=false

2.请求参数分两种类型,一种存放在url中一种放在requestBody中。

在url中的参数使用request.getParameterMap();即可获取,不会对以后的使用造成影响,而requestBody中的数据,如果在过滤器中getInputStream后就会被消耗掉,后面的程序就无法再次获取。所以需要将request对象包装一下,缓存住inputstream中的内容。

实现HttpServletRequestWrapper类 将数据缓存到byte数组中,重写getInputStream和getReader方法。

package com.jsz.peini.interceptor;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;



public class PnRequestWrapper extends HttpServletRequestWrapper {

	private final byte[] body; // 报文  
    final static int BUFFER_SIZE = 4096;  
    public PnRequestWrapper(HttpServletRequest request) throws IOException {  
        super(request);
        body = InputStreamTOByte(request.getInputStream());  
    }  
      
    @Override  
    public BufferedReader getReader() throws IOException {  
        return new BufferedReader(new InputStreamReader(getInputStream()));  
    }  
      
    @Override  
    public ServletInputStream getInputStream() throws IOException {  
        final ByteArrayInputStream bais = new ByteArrayInputStream(body);  
        return new ServletInputStream() {  
              
            @Override  
            public int read() throws IOException {  
                return bais.read();  
            }  
        };  
    }
    // 将InputStream转换成byte数组  
    public static byte[] InputStreamTOByte(InputStream in) throws IOException {  
  
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();  
  
        byte[] data = new byte[BUFFER_SIZE];  
  
        int count = -1;  
  
        while ((count = in.read(data, 0, BUFFER_SIZE)) != -1)  
  
            outStream.write(data, 0, count);  
  
        data = null;  
  
        return outStream.toByteArray();  
  
    }  
	
}

3.解决了前面的问题后实现filter

package com.jsz.peini.interceptor;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Map;

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 org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSONObject;
import com.jsz.peini.common.util.PeiniUtils;
import com.jsz.peini.common.util.ThreadUtil;

public class AccessLogFilter implements Filter {

	private static final Logger logger = LoggerFactory.getLogger(AccessLogFilter.class);
	
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {

	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		/**
		 * 判断请求
		 * 	get请求不用多余处理,获取请求参数后放行。
		 * 	post请求判断
		 * 		content-type:keyvalue获取requestmap记录
		 * 					  json 包装request获取inputstream 记录
		 * 		放行
		 * 
		 * 记录参数:访问时间-响应时间-请求的接口-请求的类型-请求的userid-请求的token-请求的ip-请求useragent-请求的parameter-请求的inputstream
		 */
		
		HttpServletRequest httpServletRequest = (HttpServletRequest) request;
		long startTime = System.currentTimeMillis(); 
		String method = httpServletRequest.getMethod();
		String accessIp = getIpAddr(httpServletRequest);
		String accessUrl = httpServletRequest.getRequestURI();
		//从header获取token 如果token未获取到,从parameter获取token(userId)
		String token = httpServletRequest.getHeader("token");
		String userId = "";
		if(StringUtils.isBlank(token)){
			token = request.getParameter("userId");
			if(StringUtils.isNotBlank(token)){
				JSONObject obj = PeiniUtils.validToken(token);
				if (obj.getInteger("resultCode") != 1) {
	
				} else {
					userId = obj.getString("userId");
				}
			}else{
				userId = token;
			}
		}else{
			userId = ThreadUtil.getThreadInfo().getUserId();
		}
		String userAgent = httpServletRequest.getHeader("User-Agent");
		String requestParameter = "";
		String requestBodyJson = "";
		ServletRequest requestWrapper = null;    
		if("GET".equals(method)){
			requestParameter = getRequestParameter(httpServletRequest);
		}else if("POST".equals(method)){
	        if(request instanceof HttpServletRequest&&"application/json".equals(((HttpServletRequest) request).getHeader("Content-Type"))) { 
	            requestWrapper = new PnRequestWrapper((HttpServletRequest) request);    
	        }    
	        if(requestWrapper == null) { 
	        	requestParameter = getRequestParameter(httpServletRequest);
	        }else{
	        	InputStream is = requestWrapper.getInputStream();
	        	StringBuilder requsetBodyBuilder = new StringBuilder ();  
	            BufferedReader streamReader = new BufferedReader (new InputStreamReader (is,"UTF-8"));  
	            String inputStr;  
	            while ((inputStr = streamReader.readLine ()) != null){
	            	requsetBodyBuilder.append (inputStr);  
	            }
	            requestBodyJson = requsetBodyBuilder.toString();
	        }
		}
		if(requestWrapper == null) { 
			chain.doFilter(request, response); 
		}else{
			chain.doFilter(requestWrapper, response);
		}
		long endTime = System.currentTimeMillis(); 
		long execteTime = endTime - startTime;
		
		logger.info("{} {} {} {} {} {} {} {} {}",execteTime,accessUrl,method,userId,token,accessIp,userAgent,requestParameter,requestBodyJson);
		
	}

	@Override
	public void destroy() {

	}

	/** 
     * 获取当前网络ip 
     * @param request 
     * @return 
     */  
    public String getIpAddr(HttpServletRequest request){  
        String ipAddress = request.getHeader("x-forwarded-for");  
            if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {  
                ipAddress = request.getHeader("Proxy-Client-IP");  
            }  
            if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {  
                ipAddress = request.getHeader("WL-Proxy-Client-IP");  
            }  
            if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {  
                ipAddress = request.getRemoteAddr();  
                if(ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")){  
                    //根据网卡取本机配置的IP  
                    InetAddress inet=null;  
                    try {  
                        inet = InetAddress.getLocalHost();  
                    } catch (UnknownHostException e) {  
                        e.printStackTrace();  
                    }  
                    ipAddress= inet.getHostAddress();  
                }  
            }  
            //对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割  
            if(ipAddress!=null && ipAddress.length()>15){ //"***.***.***.***".length() = 15  
                if(ipAddress.indexOf(",")>0){  
                    ipAddress = ipAddress.substring(0,ipAddress.indexOf(","));  
                }  
            }  
            return ipAddress;   
    }
	
	public String getRequestParameter(HttpServletRequest request){
		StringBuilder requestParameter = new StringBuilder();
		Map<String, String[]> pa = request.getParameterMap();
        for (Map.Entry<String, String[]> entry : pa.entrySet()) {
      	  requestParameter.append(entry.getKey()+":"+entry.getValue()[0]);
		}
        return requestParameter.toString();
	}
	
}

记录响应日志

记录响应内容,已开始困扰了我很久找不到合适的解决方案,拿不到response的输出流中的数据。

平时开发时除了mybatis sql有异常时日志等级设置为debug等级一般都是info等级,有次设置问debug等级后发现spring mvc会输出响应内容,追踪后是RequestResponseBodyMethodProcessor输出的。

在log4j的配置文件中为这个类配置为debug的日志等级,使用accessLog这个logger,additivity设置问false,既可以实现在日志文件中记录响应内容

log4j.logger.org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor=DEBUG,accessLog
log4j.additivity.org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor=false

 

转载于:https://my.oschina.net/u/3714931/blog/1595572

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值