CAT简介CAT(CentralApplicationTracking)是美团点评基于Java开发的开源分布式实时监控系统。美团点评基础设施部希望在基础存储、高性能通信、大规模在线访问、服务治理、实时监控、容器化、集群智能调度等领域提供业界领先的统一解决方案。CAT目前在美团点评,其产品定位是应用层统一监控组件,广泛应用于中间件(RPC、数据库、缓存、MQ等)框架,提供系统性能指标、健康度等服务各业务线状态、实时告警。准备工作对于同步请求API,CAT服务器自然是可以看到的。同步请求API的例子可以参考之前的文章《五分钟后,你将学会在SpringBoot项目中如何集成CAT调用链》。但是对于异步请求API,由于不在同一个线程,在子线程中无法获取到父线程的消息树,所以在CAT服务器上是看不到相应的请求的。首先写一个实现了Cat.Context接口的类来存储消息树的上下文信息:@OverridepublicvoidaddProperty(Stringkey,Stringvalue){properties.put(key,value);}@OverridepublicStringgetProperty(Stringkey){returnproperties.get(key);}@OverridepublicStringtoString(){return"CatContext{"+"properties="+properties+'}';}}我们可以先保存父线程消息树的上下文信息,然后在子线程中使用。先写一个存放上下文信息的地方:publicclassContextWarehouse{privatestaticThreadLocalcontextThreadLocal=newThreadLocal();publicstaticvoidsetContext(finalCatContextcontext){contextThreadLocal.set(context);}publicstaticCatContextgetContext(){//先从ContextWarehouse获取上下文信息CatContextcontext=contextThreadLocal.get();if(context==null){context=newCatContext();Cat.logRemoteCallClient(上下文);}返回上下文;}}实现Callable接口,创建自定义类实现在子线程中存储父线程上下文信息的功能:publicclassOneMoreCallableimplementsCallable{privateCatContextcatContext;私有Callable可调用;publicDdCallable(finalCallablecallable){this.callable=callable;this.catContext=newCatContext();//获取父线程消息树的上下文信息Cat.logRemoteCallClient(this.catContext);}@OverridepublicVcall()throwsException{//将父线程消息树的上下文信息保存到子线程ContextWarehouse.setContext(this.catContext);返回callable.call();}}定义一些常量,作为调用API时header中的key:publicstaticfinalStringCAT_HTTP_HEADER_PARENT_MESSAGE_ID="DD-CAT-PARENT-MESSAGE-ID";publicstaticfinalGEDER-MESOTSAStringCAT_HTTP_RO_HEAD=-MESSAGE-ID";}埋点的时候统一在调用API的HttpClient工具类中添加代码,以GET方法为例:publicclassHttpClientUtil{publicstaticStringdoGet(Stringurl)throwsIOException{HttpGethttpGet=newHttpGet(url);CloseableHttpResponseresponse=null;CloseableHttpClienthttpClient=HttpClientBuilder.create().build();Stringcontent=null;Transactiont=Cat.newTransaction(CatConstants.TYPE_CALL,url);尝试{CatContextcontext=ContextWarehuse.getContext();httpGet.setHeader(CatHttpConstants.CAT_HTTP_HEADER_ROOT_MESSAGE_ID,context.getProperty(Cat.Context.ROOT));httpGet.setHeader(CatHttpConstants.CAT_HTTP_HEADER_PARENT_MESSAGE_ID,context.getProperty(Cat.Context.PARENT));httpGet.setHeader(CatHttpConstants.CAT_HTTP_HEADER_CHILD_MESSAGE_ID,context.getProperty(Cat.Context.CHILD));响应=httpClient.execute(httpGet);如果(response.getStatusLine().getStatusCode()==200){content=EntityUtils.toString(response.getEntity(),"UTF-8");t.setStatus(交易.SUCCESS);}}catch(Exceptione){Cat.logError(e);t.setStatus(e);扔e;}finally{if(response!=null){response.close();}if(httpClient!=null){httpClient.close();}t.com完成();}返回内容;}}异步请求示例下面写一个异步请求示例,通过多个商品ID异步获取对应的商品详情:publicclassProductService{/***声明一个线程,大小固定为10Pool*/privatestaticExecutorServiceexecutor=Executors.newFixedThreadPool(10);/***通过商品ID列表异步获取对应的商品详情**@paramproductIds商品ID列表*@return对应的商品详情*/publicListfindProductInfo(ListproductIds){List>期货=newArrayList<>();for(LongproductId:productIds){futures.add(executor.submit(newDdCallable(()->{try{//调用API获取商品详情returnHttpClientUtil.doGet("http://api.product/get?id="+productId);}catch(Exceptione){return"";}})));}ListproductInfos=newArrayList<>();对于(未来<String>future:futures){try{//异步获取对应商品详情productInfos.add(future.get());}catch(Exceptione){productInfos.add("");}}返回产品信息;这样写完后,就可以在CAT服务器的Transaction报告中查看异步请求了