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

    xiaoxiao2021-04-11  34

    上次讲了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、拦截器的实现

            

    package brave.interceptor; import static com.github.kristofa.brave.internal.Util.checkNotNull; import java.net.URI; import java.net.URISyntaxException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import com.github.kristofa.brave.Brave; import com.github.kristofa.brave.ServerRequestInterceptor; import com.github.kristofa.brave.ServerResponseInterceptor; import com.github.kristofa.brave.ServerSpan; import com.github.kristofa.brave.ServerSpanThreadBinder; import com.github.kristofa.brave.http.DefaultSpanNameProvider; import com.github.kristofa.brave.http.HttpResponse; import com.github.kristofa.brave.http.HttpServerRequest; import com.github.kristofa.brave.http.HttpServerRequestAdapter; import com.github.kristofa.brave.http.HttpServerResponseAdapter; import com.github.kristofa.brave.http.SpanNameProvider; import com.github.kristofa.brave.spring.ServletHandlerInterceptor; import brave.adapter.CustomServerRequestAdapter; @Configuration public class CustomServletHandlerInterceptor extends HandlerInterceptorAdapter { static final String HTTP_SERVER_SPAN_ATTRIBUTE = ServletHandlerInterceptor.class.getName() + ".customserver-span"; /** Creates a tracing interceptor with custom */ public static CustomServletHandlerInterceptor create(Brave brave) { return new Builder(brave).build(); } public static Builder builder(Brave brave) { return new Builder(brave); } public static final class Builder { final Brave brave; SpanNameProvider spanNameProvider = new DefaultSpanNameProvider(); Builder(Brave brave) { // intentionally hidden this.brave = checkNotNull(brave, "brave"); } public Builder spanNameProvider(SpanNameProvider spanNameProvider) { this.spanNameProvider = checkNotNull(spanNameProvider, "spanNameProvider"); return this; } public CustomServletHandlerInterceptor build() { return new CustomServletHandlerInterceptor(this); } } private final ServerRequestInterceptor requestInterceptor; private final ServerResponseInterceptor responseInterceptor; private final ServerSpanThreadBinder serverThreadBinder; private final SpanNameProvider spanNameProvider; @Autowired // internal CustomServletHandlerInterceptor(SpanNameProvider spanNameProvider, Brave brave) { this(builder(brave).spanNameProvider(spanNameProvider)); } CustomServletHandlerInterceptor(Builder b) { // intentionally hidden this.requestInterceptor = b.brave.serverRequestInterceptor(); this.responseInterceptor = b.brave.serverResponseInterceptor(); this.serverThreadBinder = b.brave.serverSpanThreadBinder(); this.spanNameProvider = b.spanNameProvider; } /** * @deprecated please use {@link #create(Brave)} or {@link #builder(Brave)} */ @Deprecated public CustomServletHandlerInterceptor(ServerRequestInterceptor requestInterceptor, ServerResponseInterceptor responseInterceptor, SpanNameProvider spanNameProvider, final ServerSpanThreadBinder serverThreadBinder) { this.requestInterceptor = requestInterceptor; this.spanNameProvider = spanNameProvider; this.responseInterceptor = responseInterceptor; this.serverThreadBinder = serverThreadBinder; } @Override public boolean preHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler) { requestInterceptor.handle(new CustomServerRequestAdapter(request, spanNameProvider)); return true; } @Override public void afterConcurrentHandlingStarted(final HttpServletRequest request, final HttpServletResponse response, final Object handler) { request.setAttribute(HTTP_SERVER_SPAN_ATTRIBUTE, serverThreadBinder.getCurrentServerSpan()); serverThreadBinder.setCurrentSpan(null); } @Override public void afterCompletion(final HttpServletRequest request, final HttpServletResponse response, final Object handler, final Exception ex) { final ServerSpan span = (ServerSpan) request.getAttribute(HTTP_SERVER_SPAN_ATTRIBUTE); if (span != null) { serverThreadBinder.setCurrentSpan(span); } responseInterceptor.handle(new HttpServerResponseAdapter(new HttpResponse() { @Override public int getHttpStatusCode() { return response.getStatus(); } })); } } 2、适配器的实现

    package brave.adapter; import static com.github.kristofa.brave.IdConversion.convertToLong; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import com.github.kristofa.brave.KeyValueAnnotation; import com.github.kristofa.brave.ServerRequestAdapter; import com.github.kristofa.brave.SpanId; import com.github.kristofa.brave.TraceData; import com.github.kristofa.brave.http.BraveHttpHeaders; import com.github.kristofa.brave.http.SpanNameProvider; import zipkin.TraceKeys; public class CustomServerRequestAdapter implements ServerRequestAdapter { private final HttpServletRequest request; public CustomServerRequestAdapter(HttpServletRequest request, SpanNameProvider spanNameProvider) { this.request = request; } @Override public TraceData getTraceData() { String sampled = request.getHeader(BraveHttpHeaders.Sampled.getName()); String parentSpanId = request.getHeader(BraveHttpHeaders.ParentSpanId.getName()); String traceId = request.getHeader(BraveHttpHeaders.TraceId.getName()); String spanId = request.getHeader(BraveHttpHeaders.SpanId.getName()); // Official sampled value is 1, though some old instrumentation send true Boolean parsedSampled = sampled != null ? sampled.equals("1") || sampled.equalsIgnoreCase("true") : null; if (traceId != null && spanId != null) { return TraceData.create(getSpanId(traceId, spanId, parentSpanId, parsedSampled)); } else if (parsedSampled == null) { return TraceData.EMPTY; } else if (parsedSampled.booleanValue()) { // Invalid: The caller requests the trace to be sampled, but didn't pass IDs return TraceData.EMPTY; } else { return TraceData.NOT_SAMPLED; } } @Override public String getSpanName() { return "custom spanName"; } @Override public Collection<KeyValueAnnotation> requestAnnotations() { List<KeyValueAnnotation> kvs = new ArrayList<KeyValueAnnotation>(); Map<String, String[]> params = this.request.getParameterMap(); for(String key:params.keySet()){ KeyValueAnnotation kv = KeyValueAnnotation.create(key, params.get(key)[0]); kvs.add(kv); } KeyValueAnnotation uriAnnotation = KeyValueAnnotation.create( TraceKeys.HTTP_URL, request.getRequestURI().toString()); kvs.add(uriAnnotation); return kvs; } static SpanId getSpanId(String traceId, String spanId, String parentSpanId, Boolean sampled) { return SpanId.builder() .traceIdHigh(traceId.length() == 32 ? convertToLong(traceId, 0) : 0) .traceId(convertToLong(traceId)) .spanId(convertToLong(spanId)) .sampled(sampled) .parentId(parentSpanId == null ? null : convertToLong(parentSpanId)).build(); } }

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

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

           

    转载请注明原文地址: https://ju.6miu.com/read-667051.html

    最新回复(0)