45

调用链监控 CAT 之 URL埋点实践

 5 years ago
source link: https://mp.weixin.qq.com/s/0tLjjlUtKTyOlH-5elj0Xw
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
640?wx_fmt=gif

URL监控埋点作用

  • 一个http请求来了之后,会自动打点,能够记录每个url的访问情况,并将以此请求后续的调用链路串起来,可以在cat上查看logview 

  • 可以在cat交易及事件页面上都看到URL和URL.Forward(如果有前请求的话)两类数据;交易数据中URL点进去的数据就是被访问的具体URL(去掉参数的前缀部分)

  • 请将catFilter存放filter的第一个,这样可以保证最大可能性监控所有的请求

工程名端口作用
cat-ui8082调用入口服务
cat-business-consumer8083业务消费服务
cat-order-service8084订单服务
cat-storage-service8085库存服务
640?wx_fmt=png

上图是本节实例的埋点图,首先 cat-ui 的入口 和 调用点 加入cat埋点,cat-business-consumer的入口和调用点加入埋点,cat-order-service 和 cat-storage-service 不再调用其他微服务,所以只在入口加入埋点。通过这样的埋点,可以组成一条完整的调用链。

调用链上下文通用类

CatContextImpl.java
/**
* Cat.context接口实现类,用于context调用链传递,相关方法Cat.logRemoteCall()和Cat.logRemoteServer()
*/
public class CatContextImpl implements Cat.Context {

private Map<String, String> properties = new HashMap<>(16);

@Override
public void addProperty(String key, String value) {
properties.put(key, value);
}

@Override
public String getProperty(String key) {
return properties.get(key);
}
}
CatHttpConstants
/**
* 添加header常量,用于http协议传输rootId、parentId、childId三个context属性
*/
public class CatHttpConstants {

/**
* http header 常量
*/
public static final String CAT_HTTP_HEADER_ROOT_MESSAGE_ID = "X-CAT-ROOT-MESSAGE-ID";
public static final String CAT_HTTP_HEADER_PARENT_MESSAGE_ID = "X-CAT-ROOT-PARENT-ID";
public static final String CAT_HTTP_HEADER_CHILD_MESSAGE_ID = "X-CAT-ROOT-CHILD-ID";

}
CatServletFilter
/**
* http协议传输,远程调用链目标端接收context的filter,
* 通过header接收rootId、parentId、childId并放入CatContextImpl中,调用Cat.logRemoteCallServer()进行调用链关联
 * 注:若不涉及调用链,则直接使用cat-client.jar中提供的filter即可
 * 使用方法(视项目框架而定):
 *      1、web项目:在web.xml中引用此filter
* 2、Springboot项目,通过注入bean的方式注入此filter
*/
public class CatServletFilter implements Filter {


private String[] urlPatterns = new String[0];

@Override
public void init(FilterConfig filterConfig) throws ServletException {
String patterns = filterConfig.getInitParameter("CatHttpModuleUrlPatterns");
if (patterns != null) {
patterns = patterns.trim();
urlPatterns = patterns.split(",");
for (int i = 0; i < urlPatterns.length; i++) {
urlPatterns[i] = urlPatterns[i].trim();
}
}
}

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;

String url = request.getRequestURL().toString();
for (String urlPattern : urlPatterns) {
if (url.startsWith(urlPattern)) {
url = urlPattern;
}
}

CatContextImpl catContext = new CatContextImpl();
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, url);

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() {

}
}

本节实例中每个工程都会用到调用链上下文通用类。

cat-ui 工程

CatRestInterceptor
@Component
public class CatRestInterceptor implements ClientHttpRequestInterceptor {

@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
Transaction t = Cat.newTransaction(CatConstants.TYPE_REMOTE_CALL, request.getURI().toString());

try {
HttpHeaders headers = request.getHeaders();

// 保存和传递CAT调用链上下文
Cat.Context ctx = new CatContextImpl();
Cat.logRemoteCallClient(ctx);
headers.add(CatHttpConstants.CAT_HTTP_HEADER_ROOT_MESSAGE_ID, ctx.getProperty(Cat.Context.ROOT));
headers.add(CatHttpConstants.CAT_HTTP_HEADER_PARENT_MESSAGE_ID, ctx.getProperty(Cat.Context.PARENT));
headers.add(CatHttpConstants.CAT_HTTP_HEADER_CHILD_MESSAGE_ID, ctx.getProperty(Cat.Context.CHILD));

// 保证请求继续被执行
ClientHttpResponse response = execution.execute(request, body);
t.setStatus(Transaction.SUCCESS);
return response;
} catch (Exception e) {
Cat.getProducer().logError(e);
t.setStatus(e);
throw e;
} finally {
t.complete();
}

}
}

CatServletFilter 对 cat-ui 的入口进行了埋点,CatRestInterceptor 实现 ClientHttpRequestInterceptor接口 可以对 RestTemplate 发起的请求进行拦截,利用这一点对调用点埋点,同时在 Http Header 中存入 调用链的上下文,将调用链传递下去。

cat-business-consumer、cat-order-service、cat-storage-service 中的埋点与 cat-ui 埋点的方式相同。

curl http://127.0.0.1:8082/start

cat 监控界面可以看到本节实例的服务。

640?wx_fmt=png

点开 “logView” 可以看到完整的调用链信息。

640?wx_fmt=png

点击 “Graph” 查看图表形式的调用链信息。

640?wx_fmt=png

https://github.com/gf-huanchupk/SpringCloudLearning/tree/master/chapter15

https://github.com/dianping/cat/wiki

-- END --

640?wx_fmt=jpeg

每一个“好看”,都是对我最大的肯定!640?wx_fmt=gif


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK