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

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. 清空网站浏览记录就行啦?看Python如何实时监控网站浏览记录

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 需求: (1) 获取你对象chrome前一天的浏览记录中的所有网址(url ...

  2. 记录一次dns引发的线程池故障

    # 问题描述 公司做的是一个支付系统,会对接很多第三方公司. 突然有一天,有一家第三方(简称金花平台)反应收不到我们的通知消息. # 排查过程 我们登陆自己的服务器,检查程序日志,是有给金花平台发送通 ...

  3. 安装更强大更美观的zsh,配置oh my zsh及插件

    安装更强大更美观的zsh,配置oh my zsh及插件 #0x0 安装zsh #0x1 安装oh my zsh #0x2 配置zshrc #0x3 配置主题 #0x4 安装插件 #0x5 小结 #0x ...

  4. vue+element-ui JYAdmin后台管理系统模板-集成方案【项目搭建篇2】

    项目搭建时间:2020-06-29 本章节:讲述基于vue/cli, 项目的基础搭建. 本主题讲述了: 1.跨域配置 2.axios请求封装 3.eslint配置 4.环境dev,test,pro(开 ...

  5. 1731: [Usaco2005 dec]Layout 排队布局*

    1731: [Usaco2005 dec]Layout 排队布局 题意: n头奶牛在数轴上,不同奶牛可以在同个位置处,编号小的奶牛必须在前面.m条关系,一种是两头奶牛距离必须超过d,一种是两头奶牛距离 ...

  6. MySQL主从复制--单库复制搭建

    背景说明 负责公司MySQL数仓的搭建和维护,因为前端业务涉及到一次业务表的分库,导致整个平台新增加一台MySQL服务器,需要将该库数据通过主从复制同步至原有的数仓实例. 数据流向说明如下图: 业务环 ...

  7. Linux/Docker 中使用 System.Drawing.Common 踩坑小计

    前言 在项目迁移到 .net core 上面后,我们可以使用 System.Drawing.Common 组件来操作 Image,Bitmap 类型,实现生成验证码.二维码,图片操作等功能.Syste ...

  8. 【JVM之内存与垃圾回收篇】StringTable

    StringTable String的基本特性 String:字符串,使用一对 "" 引起来表示 String s1 = "Nemo"; // 字面量的定义方式 ...

  9. 微信扫码登陆js

    先贴一个微信开发文档教程 https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.ht ...

  10. HashMap 中 get,put 方法源码实现

    HashMap 是Map接口的一个实现类 1.线程 HashMap 非线程安全2.数据存储结构 hashMap采用Entity数组来存储 key-value对,每一个键值对组成一个Entity,键值对 ...