使用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

相关文章
|
Web App开发 新零售 前端开发
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
1.尽可能地了解需求,系统层面适用开闭原则 2.模块化,低耦合,能快速响应变化,也可以避免一个子系统的问题波及整个大系统 3.
750 0
|
Web App开发 前端开发 关系型数据库
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
fuser可用于查询文件、目录、socket端口和文件系统的使用进程 1.查询文件和目录使用者 fuser最基本的用法是查询某个文件或目录被哪个进程使用: # fuser -v .
883 0
|
Web App开发 前端开发
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
总结和计划总是让人喜悦或镇痛,一方面以前一段时间没有荒废,能给现在的行动以信心,另一方面看到一年的时间并不能完成很多事情,需要抓紧时间。
617 0
|
Web App开发 监控 前端开发
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
Datanode的日志中看到: 10/12/14 20:10:31 INFO hdfs.DFSClient: Could not obtain block blk_XXXXXXXXXXXXXXXXXXXXXX_YYYYYYYY from any node: java.
693 0
|
Web App开发 监控 前端开发
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
负载均衡: LVS(Layer 4), HAProxy(Layer 4、 7),Nginx(Layer 7) 虚拟化: LXC、KVM、Xen HA:Keepalived、Heartbeat 分布式缓存...
760 0
|
Web App开发 前端开发
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
zookeeper watch的定义如下:watch事件是一次性触发器,当watch监视的数据发生变化时,通知设置了该watch的client,即watcher。
936 0
|
Web App开发 前端开发 测试技术
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
一、迁移步骤 1.首先安装最新版本gitlab(gitlab7.2安装) 2.停止旧版本gitlab服务 3.将旧的项目文件完整导入新的gitlab   bundle exec rake gitlab:import:r...
715 0
|
Web App开发 前端开发
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
从hadoop移除机器把需要移除的机器增加到exclueds文件中,强制刷新datanode列表,等待decommission 状态正常后,即可停机下架,如有必要在namenode执行balancer操作。
680 0
|
Web App开发 前端开发
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
service cloudera-scm-agent stop service cloudera-scm-agent stop umount /var/run/cloudera-scm-agent/process umo...
760 0
下一篇
无影云桌面