springCloud微服务系列——链路跟踪第二篇——mvc链路跟踪器

目录

 

一、简介

二、思路

三、spring mvc

四、示例代码


一、简介

     这篇文章总结一下mvc链路跟踪器的实现,这篇文章的内容相对比较简单。

二、思路

      上一篇文章其实已经顺带把mvc链路跟踪器的思路说了

      1、初始化上下文,新建ThreadLoacal

      2、从http中获取traceId信息

           如果有说明是被别的服务调用,将http中的traceId和rpceId保存到上下文

           如果没有说明请求来自于客户端,新建链路跟踪信息,保存到上下文

      3、处理结束后将上下文销毁

《springCloud微服务系列——链路跟踪第一篇——设计思路以及通用链路跟踪器》

三、spring mvc

      如果controller层为spring mvc,那么可以使用拦截器拦截请求进行链路跟踪,非常简单。

四、示例代码

public class MvcTracker implements Tracker<MvcHolder> {

	private static final FastDateFormat ISO_DATETIME_TIME_ZONE_FORMAT_WITH_MILLIS = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss.SSSZZ");
	
	protected static final String BEGIN_TIME_KEY = "beginTime";
	
	protected static final String RPC_TRACE_INFO_VO_KEY = "rpcTraceInfoVO";
	
	protected TraceClient traceClient;
	
	public MvcTracker(TraceClient traceClient) {
		this.traceClient = traceClient;
	}
	
	@Override
	public void preHandle(MvcHolder holder) {
		initTraceData(holder.getRequest(), holder.getHandler(), holder.getProfile());
	}
	
	@Override
	public void postHandle(MvcHolder holder) {
		finishTraceData(holder.getRequest(), holder.getResponse(), holder.getException());
	}
	
	private void initTraceData (HttpServletRequest request, Object handler, String profile) {
		// 开始时间
		request.setAttribute(BEGIN_TIME_KEY, System.currentTimeMillis());
		// 为当前线程设置上下文
		TraceContext.init();
		// 链路跟踪信息基础对象
		TraceInfo traceInfo = new TraceInfo();
		
		String traceIdFromHeader = request.getHeader(TraceInfo.TRACE_ID_KEY);
		
		Optional.ofNullable(traceIdFromHeader)
			.ifPresent(traceId->{
			traceInfo.setTraceId(traceId);
		});
		
		Optional.ofNullable(
				request.getHeader(TraceInfo.RPC_ID_KEY)
		).ifPresent(rpcId->{
			traceInfo.setRpcId(rpcId);
		});
		
		if(traceIdFromHeader != null) {
			traceInfo.setRootRpcId(traceInfo.getRpcId());
		} else {
			traceInfo.setRootRpcId(TraceInfo.RE_ORIGINAL_ROOT_RPC_ID);
		}
		
		// 封装链路跟踪数据
		if(handler != null && handler instanceof HandlerMethod && traceIdFromHeader == null) {
			HandlerMethod handlerMethod = (HandlerMethod) handler;
			 
			Gson gson =new Gson();
			 
			String serviceName = null;
			try {
				serviceName = TargetUtils.getTarget(handlerMethod.getBean()).getClass().getSimpleName();
			} catch (Exception e) {
				 serviceName = handlerMethod.getBean().getClass().getSimpleName();
			}
			 if(serviceName == null) {
				 serviceName = handlerMethod.getBean().getClass().getSimpleName();
			 }
			 
			 RpcTraceInfoVO rpcTraceInfoVO = new RpcTraceInfoVO();
			 rpcTraceInfoVO.setProfile(profile);
			 rpcTraceInfoVO.setRequestDateTime(ISO_DATETIME_TIME_ZONE_FORMAT_WITH_MILLIS.format(Calendar.getInstance().getTime()));
			 rpcTraceInfoVO.setTraceId(traceInfo.getTraceId());
			 rpcTraceInfoVO.setRpcId(traceInfo.getRpcId());
			 rpcTraceInfoVO.setRpcType(RpcTypeEnum.HTTP.name());
			 rpcTraceInfoVO.setServiceCategory("spring mvc");
			 rpcTraceInfoVO.setServiceName(handlerMethod.getBean().getClass().getName().split("\\$\\$")[0]);
			 rpcTraceInfoVO.setMethodName(handlerMethod.getMethod().getName());
			 rpcTraceInfoVO.setRequestParam(gson.toJson(request.getParameterMap()));
			 rpcTraceInfoVO.setServiceHost(HostUtil.getIP()+":"+request.getLocalPort()+request.getServletPath());
			 rpcTraceInfoVO.setClientHost(HostUtil.getIP(request));
			 
			 request.setAttribute(RPC_TRACE_INFO_VO_KEY, rpcTraceInfoVO);
		}
		
		// 增加层级
		//traceInfo.addHierarchy();
		
		// 链路跟踪信息保存到当前线程上下文中
		TraceContext.putTraceInfo(traceInfo);
		MDC.put(TraceInfo.TRACE_ID_KEY, traceInfo.getTraceId());
		MDC.put(TraceInfo.RPC_ID_KEY, traceInfo.getRpcId());
	}
	
	private void finishTraceData(HttpServletRequest request, HttpServletResponse response, Exception ex) {
		try {
			String traceIdFromHeader = request.getHeader(TraceInfo.TRACE_ID_KEY);
			if(traceIdFromHeader != null)
				return;
			RpcTraceInfoVO rpcTraceInfoVO = (RpcTraceInfoVO) request.getAttribute(RPC_TRACE_INFO_VO_KEY);
			if(rpcTraceInfoVO != null) {
					long beginTime = (Long) request.getAttribute(BEGIN_TIME_KEY);
					rpcTraceInfoVO.setRunTime(System.currentTimeMillis() - beginTime);
					if(ex == null) {
						rpcTraceInfoVO.setResult(RpcTraceInfoVO.RESULT_SUCCESS);
					} else {
						rpcTraceInfoVO.setResult(RpcTraceInfoVO.RESULT_FAILURE);
						rpcTraceInfoVO.setResponseInfo(ex.getMessage());
					}
					Gson gson = new Gson();
					log.debug(gson.toJson(rpcTraceInfoVO));
					traceClient.sendTraceInfo(rpcTraceInfoVO);
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		} finally {
			request.removeAttribute(RPC_TRACE_INFO_VO_KEY);
			TraceContext.removeTraceInfo();
			MDC.remove(TraceInfo.TRACE_ID_KEY);
			MDC.remove(TraceInfo.RPC_ID_KEY);
		}
	}
	
}
public class SpringMvcTracker extends MvcTracker implements Tracker<MvcHolder> {

	public SpringMvcTracker (TraceClient traceClient) {
		super(traceClient);
		this.traceClient = traceClient;
	}
	
}
@Slf4j
public class TraceInteceptor extends HandlerInterceptorAdapter {

	private String profile;
	
	private Tracker<MvcHolder> tracker;
	
	public TraceInteceptor (String profile, Tracker<MvcHolder> tracker) {
		super();
		this.profile = profile;
		this.tracker = tracker;
	}
	
	/**
	 * 
	 * http请求处理前操作
	 * 
	 */
	@Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                             Object handler) throws Exception {
		log.info("http preHandle");
		if(isTraceHandler(handler)) {
			MvcHolder mvcHolder = new MvcHolder();
			mvcHolder.setProfile(profile);
			mvcHolder.setRequest(request);
			mvcHolder.setResponse(response);
			mvcHolder.setHandler(handler);
			tracker.preHandle(mvcHolder);
		}
		
		return super.preHandle(request, response, handler);
	}
	
	/**
	 * 
	 * http请求处理完操作
	 * 
	 */
	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
			@Nullable Exception ex) throws Exception {
		log.info("http afterCompletion");
		MvcHolder mvcHolder = new MvcHolder();
		mvcHolder.setRequest(request);
		mvcHolder.setResponse(response);
		mvcHolder.setHandler(handler);
		mvcHolder.setException(ex);
		tracker.postHandle(mvcHolder);
	}
	
	/**
	 * 
	 * <p>Title: isTraceHandler</p>  
	 * <p>Description: 是否被@Trace注释</p>  
	 * @param handler
	 * @return
	 */
	public boolean isTraceHandler(Object handler) {
        Object annoation = getAnnotation(handler);
        if (annoation == null)
            return false;
        Trace trace = (Trace) annoation;
        if(!trace.value().getName().equals(SpringMvcTracker.class.getName()))
        	return false;
        return true;
    }
	
	/**
	 * 
	 * <p>Title: getAnnotation</p>  
	 * <p>Description: 获得@Trace注释</p>  
	 * @param handler
	 * @return
	 */
	private Object getAnnotation(Object handler) {
		if(handler == null)
			return null;
		
    	if (!(handler instanceof HandlerMethod))
            return null;
    	
    	Object annoation = null;
    	
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        annoation = handlerMethod.getMethodAnnotation(Trace.class);
        return annoation;
    }
	
}

https://github.com/wulinfeng2/luminary-component

猜你喜欢

转载自blog.csdn.net/guduyishuai/article/details/81359765