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);
效果如下
Dropwizard+jersey+MDC实现日志跟踪以及接口响应时间统计的更多相关文章
- EF Core 日志跟踪sql语句
EF Core 日志跟踪sql语句 官方文档链接:https://docs.microsoft.com/en-us/ef/core/miscellaneous/logging 1.新增自定义ILogg ...
- 推荐windows下的日志跟踪工具:SnakeTail
用过Linux的同学都知道,在Linux中要实时跟踪日志文件那是非常的方便,Tail.Less都可以做到. 开启动态跟踪后,程序会监视文件修改,从而不断刷新出最新的内容,对于线上运维特别有用. 今 ...
- Entity Framework实体框架使用TrackerEnabledDbContext进行操作日志跟踪
在EF实体框架中进行日志跟踪,一般都是自己写个Log实体类,在数据保存时进行属性原始值验证来进行日志跟踪.当然还可以使用一些第三扩展库例如:entity framework extended进行日志记 ...
- 循序渐进看Java web日志跟踪(3)-Log4J的使用和配置
之前说过关于java日志跟踪的几大主要用的框架,也说到了,其实在其中,Log4J充当着一个相当重要的角色.目前,大部分框架也都是采用的是Log4J,虽然说它已经停止了更新,作者也重新起了LogBack ...
- 循序渐进看Java web日志跟踪(1)-Tomcat 日志追踪与配置
日志,是软件运行过程中,对各类操作中重要信息的记录. 日志跟踪,不管对于怎么样的项目来说,都是非常重要的一部分,它关系到项目后期的维护和排错,起着举足轻重的作用.项目开发过程中,对日志的记录规则,也将 ...
- 【原创】基于UDP广播的局域网Web Window Service日志跟踪小工具
一直感觉Web开发或者windows服务的日志跟踪调试不是很方便 特别是在生产环境服务器上面 目前一般的解决方案是通过各种日志工具把错误信息和调试信息 ...
- MySQL开启日志跟踪
在开发过程中有时候会遇到sql相关的问题,但是有时候代码中不会直接看到真实的sql,想要看到mysql中实际执行的是什么sql,可以通过开启日志跟踪方式查看. 1 开启日志跟踪 SET GLOBAL ...
- Mbp通过筛选器和中间件实现异常,日志,事务及接口返回数据格式化aop处理.
Mbp应用服务层的AOP实现 实现方法:asp.net core mvc 筛选器 + 中间件 日志,事务,和接口返回结果统一格式化采用操作筛选器,而异常处理采用中间件来处理. 最开始,我是打算用aut ...
- asp.net mvc,基于aop实现的接口访问统计、接口缓存等
其实asp.net 上aop现有的框架应该蛮多的,比如静态注入式的PostSharp(新版本好像已经商业化了,旧版本又不支持.net4.0+),或者通过反射的(性能会降低). 本文则是通过mvc其中一 ...
随机推荐
- CTF_show平台 web题解 part1
web3 题目描述: 方法一:RFI 使用url实现php远程文件包含 在服务器上构造1.txt <?php $a = "<?php eval(\$_POST['123'])?& ...
- java 数据结构(四):java常用类四 比较器以及其他类
比较器 1.Java比较器的使用背景: Java中的对象,正常情况下,只能进行比较:== 或 != .不能使用 > 或 < 的但是在开发场景中,我们需要对多个对象进行排序,言外之意,就需要 ...
- Windows分页文件设置不当导致SQL Server服务被终止
Windows分页文件设置不当导致SQL Server服务被终止 文章说明 在正式开始验证和测试之前,先介绍Windows分页文件和SQL Server的动态内存管理.下面测试将分为两种测试场景:场景 ...
- 微信小程序接口封装、原生接口封装、request、promise封装
相信大家在做微信小程序的时候会有很多地方需要调用接口,就和pc以及手机端一样,多个页面多次调用会有很多状态,那为了节省大家的开发时间就会需要给请求的接口做一些简单封装,便于开发,在这里我用了两个js, ...
- Docker 基础知识 - 使用卷(volume)管理应用程序数据
卷(volumes)是 Docker 容器生产和使用持久化数据的首选机制.绑定挂载(bind mounts)依赖于主机的目录结构,卷(volumes)完全由 Docker 管理.卷与绑定挂载相比有几个 ...
- Ethical Hacking - NETWORK PENETRATION TESTING(6)
Creating a fake access point (honeypot) Fake access points can be handy in many scenarios, one examp ...
- UVALive - 3644 X-Plosives (并查集)
A secret service developed a new kind of explosive that attain its volatile property only when a spe ...
- 深入掌握K8S Pod
k8s系列文章: 什么是K8S K8S configmap介绍 Pod是k8s中最小的调度单元,包含了一个"根容器"和其它用户业务容器. 如果你使用过k8s的话,当然会了解pod的 ...
- 学完自动化测试,用小技能做了点兼职刷弹幕,小赚10W
大家好,今天又给大家带来了Python爬虫的分享,继续来研究一下虎牙平台的爬虫. 起因 我冒出有一个很有趣的想法,就是,我们可以使用selenium来完成虎牙自动化登录,并且自动给主播发送弹幕功能的程 ...
- 扩展BSGS
\(BSGS\) 求解\(a^x\equiv b\pmod p\),且\(a\)与\(p\)互质 由\(a^{φ(p)}\equiv1 \pmod p\)和\(a^0\equiv 1\pmod p\) ...