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

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

效果如下

Dropwizard+jersey+MDC实现日志跟踪以及接口响应时间统计的更多相关文章

  1. EF Core 日志跟踪sql语句

    EF Core 日志跟踪sql语句 官方文档链接:https://docs.microsoft.com/en-us/ef/core/miscellaneous/logging 1.新增自定义ILogg ...

  2. 推荐windows下的日志跟踪工具:SnakeTail

    用过Linux的同学都知道,在Linux中要实时跟踪日志文件那是非常的方便,Tail.Less都可以做到. 开启动态跟踪后,程序会监视文件修改,从而不断刷新出最新的内容,对于线上运维特别有用.   今 ...

  3. Entity Framework实体框架使用TrackerEnabledDbContext进行操作日志跟踪

    在EF实体框架中进行日志跟踪,一般都是自己写个Log实体类,在数据保存时进行属性原始值验证来进行日志跟踪.当然还可以使用一些第三扩展库例如:entity framework extended进行日志记 ...

  4. 循序渐进看Java web日志跟踪(3)-Log4J的使用和配置

    之前说过关于java日志跟踪的几大主要用的框架,也说到了,其实在其中,Log4J充当着一个相当重要的角色.目前,大部分框架也都是采用的是Log4J,虽然说它已经停止了更新,作者也重新起了LogBack ...

  5. 循序渐进看Java web日志跟踪(1)-Tomcat 日志追踪与配置

    日志,是软件运行过程中,对各类操作中重要信息的记录. 日志跟踪,不管对于怎么样的项目来说,都是非常重要的一部分,它关系到项目后期的维护和排错,起着举足轻重的作用.项目开发过程中,对日志的记录规则,也将 ...

  6. 【原创】基于UDP广播的局域网Web Window Service日志跟踪小工具

           一直感觉Web开发或者windows服务的日志跟踪调试不是很方便          特别是在生产环境服务器上面          目前一般的解决方案是通过各种日志工具把错误信息和调试信息 ...

  7. MySQL开启日志跟踪

    在开发过程中有时候会遇到sql相关的问题,但是有时候代码中不会直接看到真实的sql,想要看到mysql中实际执行的是什么sql,可以通过开启日志跟踪方式查看. 1 开启日志跟踪 SET GLOBAL ...

  8. Mbp通过筛选器和中间件实现异常,日志,事务及接口返回数据格式化aop处理.

    Mbp应用服务层的AOP实现 实现方法:asp.net core mvc 筛选器 + 中间件 日志,事务,和接口返回结果统一格式化采用操作筛选器,而异常处理采用中间件来处理. 最开始,我是打算用aut ...

  9. asp.net mvc,基于aop实现的接口访问统计、接口缓存等

    其实asp.net 上aop现有的框架应该蛮多的,比如静态注入式的PostSharp(新版本好像已经商业化了,旧版本又不支持.net4.0+),或者通过反射的(性能会降低). 本文则是通过mvc其中一 ...

随机推荐

  1. 数据库周刊31丨openGauss 正式开源;7月数据库排行榜发布;浙江移动国产数据库AntDB迁移;oracle ADG跨版本搭建;PG解决社保问题;mysqlbinlog解析……

    摘要:墨天轮数据库周刊第31期发布啦,每周1次推送本周数据库相关热门资讯.精选文章.干货文档. 热门资讯 1.openGauss 正式开源,华为公开发布源代码[摘要]6月1日,华为正式宣布开源数据库能 ...

  2. Zookeeper是什么&怎么用

    1.Zookeeper概述 Zookeeper 是一个开源的分布式协调服务框架 ,主要用来解决分布式集群中应用系统的一致性问题和数据管理问题 2:Zookeeper的特点 Zookeeper 本质上是 ...

  3. 机器学习实战基础(二十七):sklearn中的降维算法PCA和SVD(八)PCA对手写数字数据集的降维

    PCA对手写数字数据集的降维 1. 导入需要的模块和库 from sklearn.decomposition import PCA from sklearn.ensemble import Rando ...

  4. 关于Haskell计算斐波那契数列的思考

    背景 众所周知,Haskell语言是一门函数式编程语言.函数式编程语言的一大特点就是数值和对象都是不可变的,而这与经常需要对状态目前的值进行修改的动态规划算法似乎有些"格格不入", ...

  5. bzoj2561最小生成树

    bzoj2561最小生成树 题意: 给定一个连通无向图,假设现在加入一条边权为L的边(u,v),求需要删掉最少多少条边,才能够使得这条边既可能出现在最小生成树上,也可能出现在最大生成树上. 题解: 最 ...

  6. [Qt2D绘图]-03坐标系统之坐标变换

    大纲:     基本变换         介绍和常用API     窗口-视口转换         窗口         视口         让窗口和视口维持相同宽高比来防止变形   基本变换 默认 ...

  7. P2058 海港 (洛谷)

    这个题复制过来真的有点恶心,懒得手打,以后再搬题面吧. 今天我双更了,AC这个题我就完成某谷春令营第一课的作业了(假的) 这个题是个双指针.非常友善.一直往里读入就可以了,遇见不是一条船的乘客输出这一 ...

  8. 6.ALOHA协议

    动态媒体接入控制/多点接入特点:信道并非在用户通信时固定分配给用户. 一.纯ALOHA协议 纯 ALOHA协议思想:不监听信道,不按时间槽发送,随机重发.想发就发 二.时隙ALOHA协议 时隙 ALO ...

  9. PyQt5绘图

    QPainter 功能:QPainter实现在QWidget上画图功能 说明:绘图必须在paintEvent中完成,且要在bengin和end之间作图 接口: 方法 描述 begin 开始画图 end ...

  10. [jvm] -- 类加载过程篇

    类加载过程 系统加载 Class 类型的文件主要三步 加载 通过全类名获取定义此类的二进制字节流 将字节流所代表的静态存储结构转换为方法区的运行时数据结构 在内存中生成一个代表该类的 Class对象, ...