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

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. class文件的基本结构及proxy源码分析二

    前文地址:https://www.cnblogs.com/tera/p/13267630.html 本系列文章主要是博主在学习spring aop的过程中了解到其使用了java动态代理,本着究根问底的 ...

  2. Babel:下一代Javascript语法编译器

    定义 Babel是一个Javascript的编译器,通过它你可以将一些新版本的ECMAScript语法转换成低版本的语法.以便能够在低版本的浏览器或者其它环境平稳运行. 截至目前笔者写这篇文章的时候, ...

  3. 12C oracle 12.1.0.2版本打补丁

    从support  1454618.1文档 中可以下载到各版本的补丁和PSU. 此次采用的是28349311 版本号的psu 和28440711 版本号的jvm.opatch版本号6880880_12 ...

  4. swagger -- 前后端分离的API接口

    文章目录 一.背景 二.swagger介绍 三.在maven+springboot项目中使用swagger 四.swagger在项目中的好处 五.美化界面 参考链接:5分钟学会swagger配置 参考 ...

  5. 高效C++:构造/析构/赋值

    了解C++默认提供和调用的函数 编译器会自动为每一个空类创建构造函数.拷贝构造函数.赋值运算符以及析构函数 不要使用编译器自动创建的函数,要杜绝这种情况发生,自己编写这些函数 如果不想使用编译器自动生 ...

  6. 一起学Blazor WebAssembly 开发(2)

    上篇文章讲了Blazor的两种模式的区别及各自的使用场景,本篇就开始学习WebAssembly模式,本篇主要学习的是创建项目及认识项目结构: 创建项目 选择Blazor应用 选择WebAssembly ...

  7. jenkins集群(一) -- 在Linux上部署

    一.安装好jdk.maven.git 1.安装jdk并配置好全局变量 2.安装maven:yum install maven 3.安装jdk:yum install git 二 .安装jenkins ...

  8. NoSQL和SQL怎么选用?

    NoSQL 有分很多种,其中key-value NoSQL (Redis, MemcacheD, etc) 的选用相对比较清楚些,大多是当后端Data storage的cache层来用.这篇主要想请教 ...

  9. 理解k8s资源限制系列(二):cpu time

    本文介绍几种在K8S中限制资源使用的几种方法. 资源类型 在K8S中可以对两类资源进行限制:cpu和内存. CPU的单位有: 正实数,代表分配几颗CPU,可以是小数点,比如0.5代表0.5颗CPU,意 ...

  10. for循环运用,三角形

    用for循环打出三角形.倒三角形.金字塔.99乘法表 三角形: 打出如图三角形,分析行数与*个数的关系,用for循环 for(var i=0;i<5;++i){//i表示行数 var str=& ...