使用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、拦截器的实现
- 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/, 查看跟踪结果