• 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);

    效果如下

  • 相关阅读:
    Mini2440裸机开发之MMU
    Mini2440裸机开发之IIC
    Mini2440裸机开发之SPI
    Mini2440裸机开发之存储器控制器
    Mini2440裸机开发之模数转换开发
    Mini2440裸机开发之LCD编程(GB2312、ASCII字库制作)
    Python pandas df.iloc[:, 0] 取确定列值作双轴图
    python plot 画双坐标轴 设置百分比展示 和字体等细节
    python Sqlserver数据库画双轴图
    windows下Idea中用Python访问oracle数据库的方法
  • 原文地址:https://www.cnblogs.com/jiawen010/p/12703069.html
Copyright © 2020-2023  润新知