使用Zipkin 和 Brave 实现http(springmvc)服务调用跟踪(二)

简介:

使用Zipkin 和 Brave 实现http(springmvc)服务调用跟踪(二)

上次讲了Brave为Spring提供的Servlet拦截器(ServletHandlerInterceptor)及Rest(BraveClientHttpRequestInterceptor)模板的拦截器,向zipkin报告监控数据,其中,BraveClientHttpRequestInterceptor负责cs与cr的处理,ServletHandlerInterceptor负责sr与ss的处理,并没有记录到请求参数的监控及使用的是默认的span名称,那如何才能记录请求参数及修改span名称。

需要实现自定义拦截器,我选择在服务端做处理记录请求参数的过程,先看看Brave提供服务端拦截器ServletHandlerInterceptor的源码实现,发现使用HttpServerRequestAdapter适配器,

再跟踪HttpServerRequestAdapter源码,在其中实现ServerRequestAdapter接口,包括跟踪数据的获取,span名称的获取及键值数据的添加。

那我们除了实现自定义拦截器,还需要实现自己的适配器,适配器实现接口ServerRequestAdapter,在获取键值数据的方法中实现添加请求参数到keyvalue,在span名称获取方法返回自己span名称,即完成了请求参数的添加及span名称的自定义

以下实现在上篇中提供的git的工程中实现,可直接下载,git地址:https://github.com/blacklau/brave-webmvc-example

1、拦截器的实现

 

[java] view plain copy

  1. package brave.interceptor;
  2. import static com.github.kristofa.brave.internal.Util.checkNotNull;
  3. import java.net.URI;
  4. import java.net.URISyntaxException;
  5. import javax.servlet.http.HttpServletRequest;
  6. import javax.servlet.http.HttpServletResponse;
  7. import org.springframework.beans.factory.annotation.Autowired;
  8. import org.springframework.context.annotation.Configuration;
  9. import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
  10. import com.github.kristofa.brave.Brave;
  11. import com.github.kristofa.brave.ServerRequestInterceptor;
  12. import com.github.kristofa.brave.ServerResponseInterceptor;
  13. import com.github.kristofa.brave.ServerSpan;
  14. import com.github.kristofa.brave.ServerSpanThreadBinder;
  15. import com.github.kristofa.brave.http.DefaultSpanNameProvider;
  16. import com.github.kristofa.brave.http.HttpResponse;
  17. import com.github.kristofa.brave.http.HttpServerRequest;
  18. import com.github.kristofa.brave.http.HttpServerRequestAdapter;
  19. import com.github.kristofa.brave.http.HttpServerResponseAdapter;
  20. import com.github.kristofa.brave.http.SpanNameProvider;
  21. import com.github.kristofa.brave.spring.ServletHandlerInterceptor;
  22. import brave.adapter.CustomServerRequestAdapter;
  23. @Configuration
  24. public class CustomServletHandlerInterceptor  extends HandlerInterceptorAdapter {
  25.     static final String HTTP_SERVER_SPAN_ATTRIBUTE = ServletHandlerInterceptor.class.getName() + ".customserver-span";
  26.     /** Creates a tracing interceptor with custom */
  27.     public static CustomServletHandlerInterceptor create(Brave brave) {
  28.         return new Builder(brave).build();
  29.     }
  30.     public static Builder builder(Brave brave) {
  31.         return new Builder(brave);
  32.     }
  33.     public static final class Builder {
  34.         final Brave brave;
  35.         SpanNameProvider spanNameProvider = new DefaultSpanNameProvider();
  36.         Builder(Brave brave) { // intentionally hidden
  37.             this.brave = checkNotNull(brave, "brave");
  38.         }
  39.         public Builder spanNameProvider(SpanNameProvider spanNameProvider) {
  40.             this.spanNameProvider = checkNotNull(spanNameProvider, "spanNameProvider");
  41.             return this;
  42.         }
  43.         public CustomServletHandlerInterceptor build() {
  44.             return new CustomServletHandlerInterceptor(this);
  45.         }
  46.     }
  47.     private final ServerRequestInterceptor requestInterceptor;
  48.     private final ServerResponseInterceptor responseInterceptor;
  49.     private final ServerSpanThreadBinder serverThreadBinder;
  50.     private final SpanNameProvider spanNameProvider;
  51.     @Autowired // internal
  52.     CustomServletHandlerInterceptor(SpanNameProvider spanNameProvider, Brave brave) {
  53.         this(builder(brave).spanNameProvider(spanNameProvider));
  54.     }
  55.     CustomServletHandlerInterceptor(Builder b) { // intentionally hidden
  56.         this.requestInterceptor = b.brave.serverRequestInterceptor();
  57.         this.responseInterceptor = b.brave.serverResponseInterceptor();
  58.         this.serverThreadBinder = b.brave.serverSpanThreadBinder();
  59.         this.spanNameProvider = b.spanNameProvider;
  60.     }
  61.     /**
  62.      * @deprecated please use {@link #create(Brave)} or {@link #builder(Brave)}
  63.      */
  64.     @Deprecated
  65.     public CustomServletHandlerInterceptor(ServerRequestInterceptor requestInterceptor, ServerResponseInterceptor responseInterceptor, SpanNameProvider spanNameProvider, final ServerSpanThreadBinder serverThreadBinder) {
  66.         this.requestInterceptor = requestInterceptor;
  67.         this.spanNameProvider = spanNameProvider;
  68.         this.responseInterceptor = responseInterceptor;
  69.         this.serverThreadBinder = serverThreadBinder;
  70.     }
  71.     @Override
  72.     public boolean preHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler) {
  73.         requestInterceptor.handle(new CustomServerRequestAdapter(request, spanNameProvider));
  74.         return true;
  75.     }
  76.     @Override
  77.     public void afterConcurrentHandlingStarted(final HttpServletRequest request, final HttpServletResponse response, final Object handler) {
  78.         request.setAttribute(HTTP_SERVER_SPAN_ATTRIBUTE, serverThreadBinder.getCurrentServerSpan());
  79.         serverThreadBinder.setCurrentSpan(null);
  80.     }
  81.     @Override
  82.     public void afterCompletion(final HttpServletRequest request, final HttpServletResponse response, final Object handler, final Exception ex) {
  83.         final ServerSpan span = (ServerSpan) request.getAttribute(HTTP_SERVER_SPAN_ATTRIBUTE);
  84.         if (span != null) {
  85.             serverThreadBinder.setCurrentSpan(span);
  86.         }
  87.        responseInterceptor.handle(new HttpServerResponseAdapter(new HttpResponse() {
  88.            @Override
  89.            public int getHttpStatusCode() {
  90.                return response.getStatus();
  91.            }
  92.        }));
  93.     }
  94. }

2、适配器的实现

[java] view plain copy

  1. package brave.adapter;
  2. import static com.github.kristofa.brave.IdConversion.convertToLong;
  3. import java.util.ArrayList;
  4. import java.util.Collection;
  5. import java.util.Collections;
  6. import java.util.List;
  7. import java.util.Map;
  8. import javax.servlet.http.HttpServletRequest;
  9. import com.github.kristofa.brave.KeyValueAnnotation;
  10. import com.github.kristofa.brave.ServerRequestAdapter;
  11. import com.github.kristofa.brave.SpanId;
  12. import com.github.kristofa.brave.TraceData;
  13. import com.github.kristofa.brave.http.BraveHttpHeaders;
  14. import com.github.kristofa.brave.http.SpanNameProvider;
  15. import zipkin.TraceKeys;
  16. public class CustomServerRequestAdapter  implements ServerRequestAdapter {
  17.     private final HttpServletRequest request;
  18.     public CustomServerRequestAdapter(HttpServletRequest request, SpanNameProvider spanNameProvider) {
  19.         this.request = request;
  20.     }
  21.     @Override
  22.     public TraceData getTraceData() {
  23.         String sampled = request.getHeader(BraveHttpHeaders.Sampled.getName());
  24.         String parentSpanId = request.getHeader(BraveHttpHeaders.ParentSpanId.getName());
  25.         String traceId = request.getHeader(BraveHttpHeaders.TraceId.getName());
  26.         String spanId = request.getHeader(BraveHttpHeaders.SpanId.getName());
  27.         // Official sampled value is 1, though some old instrumentation send true
  28.         Boolean parsedSampled = sampled != null
  29.             ? sampled.equals("1") || sampled.equalsIgnoreCase("true")
  30.             : null;
  31.         if (traceId != null && spanId != null) {
  32.             return TraceData.create(getSpanId(traceId, spanId, parentSpanId, parsedSampled));
  33.         } else if (parsedSampled == null) {
  34.             return TraceData.EMPTY;
  35.         } else if (parsedSampled.booleanValue()) {
  36.             // Invalid: The caller requests the trace to be sampled, but didn't pass IDs
  37.             return TraceData.EMPTY;
  38.         } else {
  39.             return TraceData.NOT_SAMPLED;
  40.         }
  41.     }
  42.     @Override
  43.     public String getSpanName() {
  44.         return "custom spanName";
  45.     }
  46.     @Override
  47.     public Collection<KeyValueAnnotation> requestAnnotations() {
  48.         List<KeyValueAnnotation> kvs = new ArrayList<KeyValueAnnotation>();
  49.         Map<String, String[]> params = this.request.getParameterMap();
  50.         for(String key:params.keySet()){
  51.             KeyValueAnnotation kv = KeyValueAnnotation.create(key, params.get(key)[0]);
  52.             kvs.add(kv);
  53.         }
  54.         KeyValueAnnotation uriAnnotation = KeyValueAnnotation.create(
  55.                 TraceKeys.HTTP_URL, request.getRequestURI().toString());
  56.         kvs.add(uriAnnotation);
  57.         return kvs;
  58.     }
  59.     static SpanId getSpanId(String traceId, String spanId, String parentSpanId, Boolean sampled) {
  60.         return SpanId.builder()
  61.             .traceIdHigh(traceId.length() == 32 ? convertToLong(traceId, 0) : 0)
  62.             .traceId(convertToLong(traceId))
  63.             .spanId(convertToLong(spanId))
  64.             .sampled(sampled)
  65.             .parentId(parentSpanId == null ? null : convertToLong(parentSpanId)).build();
  66.    }
  67. }

 

浏览器输入测试: http://localhost:80810brave-webmvc-example/a?service=account.user.login

打开zipkin:  http://localhost:9411/, 查看跟踪结果

原文地址http://www.bieryun.com/1923.html

相关文章
|
XML 前端开发 Java
spring mvc 实现远程服务调用的几种方式
org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter 实现远程服务调用 (1)httpinvoker方式 服务器客户端都是spring时推荐这种方式 服务端 必须要实现 bean实体类  service接口类  serviceImpl服务实现类 客户端只需拷贝 bean 实体类  service接口类(
4364 0
|
2月前
|
设计模式 前端开发 JavaScript
Spring MVC(一)【什么是Spring MVC】
Spring MVC(一)【什么是Spring MVC】
|
13天前
|
设计模式 前端开发 Java
【Spring MVC】快速学习使用Spring MVC的注解及三层架构
【Spring MVC】快速学习使用Spring MVC的注解及三层架构
18 1
|
16天前
|
前端开发 Java 应用服务中间件
Spring框架第六章(SpringMVC概括及基于JDK21与Tomcat10创建SpringMVC程序)
Spring框架第六章(SpringMVC概括及基于JDK21与Tomcat10创建SpringMVC程序)
|
7天前
|
XML Java 数据格式
SpringMVC的XML配置解析-spring18
SpringMVC的XML配置解析-spring18
|
7天前
|
应用服务中间件
从代码角度戳一下springMVC的运行过程-spring16
从代码角度戳一下springMVC的运行过程-spring16
|
2月前
|
前端开发 Java 关系型数据库
基于ssm框架旅游网旅游社交平台前后台管理系统(spring+springmvc+mybatis+maven+tomcat+html)
基于ssm框架旅游网旅游社交平台前后台管理系统(spring+springmvc+mybatis+maven+tomcat+html)
|
2月前
|
移动开发 Java 测试技术
Spring MVC+Spring+Mybatis实现支付宝支付功能(附完整代码)
Spring MVC+Spring+Mybatis实现支付宝支付功能(附完整代码)
53 1
|
9月前
|
前端开发 Java Go
Spring MVC 和 Spring Boot 的区别
Spring MVC 和 Spring Boot 的区别
153 0