五分钟后,你将学会在SpringBoot项目中如何集成CAT调用链
程序员文章站
2022-06-07 10:59:46
CAT(Central Application Tracking),是美团点评基于 Java 开发的一套开源的分布式实时监控系统。在SpringBoot项目中如何集成CAT的分布式调用链功能呢? ......
买买买结算系统
一年一度的双十一购物狂欢节就要到了,又到剁手党们开始表演的时刻了。当我们把种草很久的商品放入购物车以后,点击“结算”按钮时,就来到了买买买必不可少的结算页面了。让我们虚拟一个买买买结算系统,为结算页面提供商品、促销、库存等结算信息,就此系统展开如何在springboot项目中集成cat调用链。买买买结算系统包含以下4个项目:
- 结算ui:为前端页面提供结算的基础数据。
- 购物车api:获取用户购物车中有哪些商品。
- 商品api:获取商品详细信息
- 商品促销api:获取商品的促销信息
- 商品库存api:获取商品的库存信息
时序图如下:
通过maven添加依赖
<dependency> <groupid>com.dianping.cat</groupid> <artifactid>cat-client</artifactid> <version>3.0.0</version> </dependency>
配置client.xml
创建/data/appdatas/cat/
目录,并创建client.xml
文件:
<?xml version="1.0" encoding="utf-8"?> <config xmlns:xsi="http://www.w3.org/2001/xmlschema" xsi:nonamespaceschemalocation="config.xsd"> <servers> <server ip="127.0.0.1" port="2280" http-port="8080" /> </servers> </config>
注意:把127.0.0.1替换成cat服务端的ip。
配置项目名称
买买买结算系统中一共有5个项目,每个项目都需要配置各自的项目名称。
首先,在每个项目中创建如下文件:src/main/resources/meta-inf/app.properties
然后,在每个项目里添加如下内容:
- 结算ui:
app.name=buy-buy-buy-checkout
- 购物车api:
app.name=buy-buy-buy-cart
- 商品api:
app.name=buy-buy-buy-product
- 商品促销api:
app.name=buy-buy-buy-promotion
- 商品库存api:
app.name=buy-buy-buy-store
注意:项目名称只能包含英文字母 (a-z, a-z)、数字 (0-9)、下划线 (_) 和中划线 (-)
准备埋点
在埋点之前,需要先写两个公共类,方便之后埋点时调用。
- 第一个类实现cat.context接口,用于存放调用链上下文信息:
public class catcontext implements cat.context { private map<string, string> properties = new hashmap<>(); @override public void addproperty(string key, string value) { properties.put(key, value); } @override public string getproperty(string key) { return properties.get(key); } @override public string tostring() { return "catcontext{" + "properties=" + properties + '}'; } }
- 第二个类中定义一些常量,在调用api时作为header中的key。
public class cathttpconstants { public static final string cat_http_header_child_message_id = "dd-cat-child-message-id"; public static final string cat_http_header_parent_message_id = "dd-cat-parent-message-id"; public static final string cat_http_header_root_message_id = "dd-cat-root-message-id"; }
开始埋点
使用cat进行分布式调用链监控,需要修改项目中的代码进行埋点:
- 在刚刚接收到请求时进行埋点。
- 在准备调用api时进行埋点。
那么在买买买结算系统中需要做哪些代码修改呢?看一下时序图的变化就明白了:
第一个埋点,在刚刚接收到请求时,这里使用filter实现,代码如下:
public class catservletfilter implements filter { @override public void init(filterconfig filterconfig) throws servletexception { } @override public void dofilter(servletrequest servletrequest, servletresponse servletresponse, filterchain filterchain) throws ioexception, servletexception { httpservletrequest request = (httpservletrequest) servletrequest; catcontext catcontext = new catcontext(); catcontext.addproperty(cat.context.root, request.getheader(cathttpconstants.cat_http_header_root_message_id)); catcontext.addproperty(cat.context.parent, request.getheader(cathttpconstants.cat_http_header_parent_message_id)); catcontext.addproperty(cat.context.child, request.getheader(cathttpconstants.cat_http_header_child_message_id)); cat.logremotecallserver(catcontext); transaction t = cat.newtransaction(catconstants.type_url, request.getrequesturi()); try { cat.logevent("service.method", request.getmethod(), message.success, request.getrequesturl().tostring()); cat.logevent("service.client", request.getremotehost()); filterchain.dofilter(servletrequest, servletresponse); t.setstatus(transaction.success); } catch (exception ex) { t.setstatus(ex); cat.logerror(ex); throw ex; } finally { t.complete(); } } @override public void destroy() { } }
filter已经写好了,接下来还需要把filter注册到springboot中:
@configuration public class catconfiguration { @bean public filterregistrationbean catservletfilter() { filterregistrationbean registration = new filterregistrationbean(); catservletfilter filter = new catservletfilter(); registration.setfilter(filter); registration.addurlpatterns("/*"); registration.setname("cat-servlet-filter"); registration.setorder(1); return registration; } }
第两个埋点,在调用api的httpclient工具类中统一增加代码,以get方式为例:
public static string doget(string url) throws ioexception { httpget httpget = new httpget(url); closeablehttpresponse response = null; closeablehttpclient httpclient = httpclientbuilder.create().build(); string content = null; transaction t = cat.newtransaction(catconstants.type_call, url); try { context ctx = new catcontext(); cat.logremotecallclient(ctx); httpget.setheader(cathttpconstants.cat_http_header_root_message_id, ctx.getproperty(cat.context.root)); httpget.setheader(cathttpconstants.cat_http_header_parent_message_id, ctx.getproperty(cat.context.parent)); httpget.setheader(cathttpconstants.cat_http_header_child_message_id, ctx.getproperty(cat.context.child)); response = httpclient.execute(httpget); if (response.getstatusline().getstatuscode() == 200) { content = entityutils.tostring(response.getentity(), "utf-8"); t.setstatus(transaction.success); } } catch (exception e) { cat.logerror(e); t.setstatus(e); throw e; } finally { if (response != null) { response.close(); } if (httpclient != null) { httpclient.close(); } t.complete(); } return content; }
结语
以上便是springboot集成cat调用链的整个实例了,可以灵活应用,更加优雅的集成到实际项目中。
另外,cat还有很多丰富的功能,可参见。
上一篇: 写日志