Dropwizard+jersey+MDC实现日志跟踪以及接口响应时间统计

一、实现接口响应时间统计

1.1添加全局请求过滤器并注册

import org.apache.log4j.MDC;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;

/**
 * @Autor zhangjiawen
 * @Date: 2020/4/10 13:33
 */

@Provider
public class RequestLogFilter implements ContainerRequestFilter, ContainerResponseFilter {
    private final String BEGIN_LOG="beginLog";
    private static final Logger logger = LoggerFactory.getLogger(RequestLogFilter.class);



    @Override
    public void filter(ContainerRequestContext requestContext)  {
        try {
            String traceId = TraceLogUtils.getTraceId();
            MDC.put(Constants.LOG_TRACE_ID, traceId);
            LogBean logBean = new LogBean(traceId, System.currentTimeMillis());
            // MDC.put(traceId,logBean);  也可将请求参数放到MDC不用缓存,但是我用MDC存对象报类型转换异常不知咋回事,故缓存缓存保存
            requestContext.setProperty(BEGIN_LOG, traceId);
            LogThreadPoolExecutor.getInstance().getThreadPool().submit(() -> {
                //将请求存入缓存
                RequestCache.getInstance().add(logBean.getTraceID(), logBean);
                logger.info("traceid:" + logBean.getTraceID() + " uri: " + requestContext.getUriInfo().getRequestUri()
                        + " method:" + requestContext.getMethod()
                        + " parameters:" + requestContext.getUriInfo().getPathParameters().toString());
            });
        }catch (Exception e){
            e.printStackTrace();
        }


    }

    @Override
    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)  {
        try{
            long currentTime=System.currentTimeMillis();
            if(requestContext.getProperty(BEGIN_LOG)!=null){
            String  traceID=(String) requestContext.getProperty(BEGIN_LOG);
            LogThreadPoolExecutor.getInstance().getThreadPool().submit(() -> {
                try {
                    //读取traceid  异步去缓存中取 并消费
                    LogBean logBean = RequestCache.getInstance().get(traceID);
                    StringBuilder sb = new StringBuilder();
                    sb.append("traceid:" + logBean.getTraceID()).append(" ,").append(responseContext.getStatus()).append(" ,")
                            .append(responseContext.getStatusInfo()).append(",  response:{");
                    if(responseContext.getStatus()== Response.Status.CREATED.getStatusCode()){  //文件上传类型没有Entity 故单独处理
                        sb.append(responseContext.getHeaders().getFirst("Location"));
                    }else if(responseContext.getEntity()!=null){
                    sb.append(responseContext.getEntity());}                   
                    sb.append("} usedTime:").append((currentTime - logBean.getRequestDate()) + "(ms)");
                    logger.info(sb.toString());
                    RequestCache.getInstance().remove(traceID);
                    MDC.clear();
                }catch (Exception e){
                    e.printStackTrace();
                }
            });
        }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

注册过滤器

environment.jersey().register(RequestLogFilter.class);

缓存类

import java.util.concurrent.ConcurrentHashMap;

/**
 * @Autor zhangjiawen
 * @Date: 2020/4/13 8:55
 */
public class RequestCache {
    private  ConcurrentHashMap<String, LogBean> requesMap=null;

    private RequestCache(){
        requesMap=new ConcurrentHashMap<>();
    }

    private static RequestCache instance = new RequestCache();

    public static RequestCache getInstance(){
        return instance;
    }

    public void  add(String key,LogBean logBean){
        this.requesMap.put(key,logBean);
    }
    public LogBean get(String key){
       return this.requesMap.get(key);
    }
    public void remove(String key){
        this.requesMap.remove(key);
    }

}

线程池

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @Autor zhangjiawen
 * @Date: 2020/4/13 15:48
 */
public class LogThreadPoolExecutor {
    private ThreadPoolExecutor tpe =null;
    BlockingQueue<Runnable> bq = new ArrayBlockingQueue<Runnable>(10);
    private static LogThreadPoolExecutor logThreadPool=new LogThreadPoolExecutor();

    private LogThreadPoolExecutor(){
        tpe= new ThreadPoolExecutor(5,
                10,
                500,
                TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<Runnable>(10));
    }
    public static LogThreadPoolExecutor  getInstance(){
        return logThreadPool;
    }
    public ThreadPoolExecutor getThreadPool(){
        return this.tpe;
    }


}

常量类

/**
 * @Autor zhangjiawen
 * @Date: 2020/4/13 10:15
 */
public class Constants {

    /**
     * 日志跟踪id名。
     */
    public static final String LOG_TRACE_ID = "traceid";

    /**
     * 请求头跟踪id名。
     */
    public static final String HTTP_HEADER_TRACE_ID = "app_trace_id";
}

日志实体类

import java.io.Serializable;
import java.util.UUID;

/**
 * @Autor zhangjiawen
 * @Date: 2020/4/10 15:43
 */

public class LogBean implements Serializable {
    private String traceID;
    private long requestDate;

    public LogBean(String traceID, long requestDate) {
        this.traceID = traceID;
        this.requestDate = requestDate;
    }

    public LogBean(long requestDate) {
        this.requestDate = requestDate;
        this.traceID=UUID.randomUUID().toString();
    }

    public String getTraceID() {
        return traceID;
    }

    public void setTraceID(String traceID) {
        this.traceID = traceID;
    }

    public long getRequestDate() {
        return requestDate;
    }

    public void setRequestDate(long requestDate) {
        this.requestDate = requestDate;
    }
}

 

 

二、实现日志报错跟踪(为每个异常添加一个串联的traceid)

添加一个全局异常过滤器

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

/**全局异常过滤
 * @Autor zhangjiawen
 * @Date: 2020/4/13 11:24
 */
@Provider
public class GlobalTraceException implements ExceptionMapper<Exception> {
    private static final Logger logger = LoggerFactory.getLogger(GlobalTraceException.class);
    @Override
    public Response toResponse(Exception  e) {
        Response.ResponseBuilder responseBuilder = null;
        try {
            StringBuilder sb = new StringBuilder();
            sb.append(Constants.LOG_TRACE_ID + ": ").append(MDC.get(Constants.LOG_TRACE_ID) == null ? "" : MDC.get(Constants.LOG_TRACE_ID));
        //此处将MDC中traceid 取出并加到报错信息前边 logger.error(sb
+ " error: {}", e.getMessage(), e); ErrorEntity entity = new ErrorEntity(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e.getMessage()); responseBuilder = Response.ok(entity); }catch (Exception e2){ e2.printStackTrace(); } return responseBuilder.build(); } }

错误实体类

//import javax.xml.bind.annotation.XmlRootElement;

/**
 * @Autor zhangjiawen
 * @Date: 2020/4/13 13:23
 */
//@XmlRootElement//标识该资源可以被jersey转为json或者xml
public class ErrorEntity {
    private int resp_err_code;
    private String resp_err_msg;

    public ErrorEntity(int resp_err_code, String resp_err_msg) {
        this.resp_err_code = resp_err_code;
        this.resp_err_msg = resp_err_msg;
    }

    public int getResp_err_code() {
        return resp_err_code;
    }

    public void setResp_err_code(int resp_err_code) {
        this.resp_err_code = resp_err_code;
    }

    public String getResp_err_msg() {
        return resp_err_msg;
    }

    public void setResp_err_msg(String resp_err_msg) {
        this.resp_err_msg = resp_err_msg;
    }
}

注册过滤器

environment.jersey().register(GlobalTraceException.class);

效果如下

 

posted @ 2020-04-15 09:10  valar-dohaeris  阅读(692)  评论(0编辑  收藏  举报