首先引入maven相关依赖
<brave.version>3.16.0</brave.version>
<zipkin.reporter.version>1.1.2</zipkin.reporter.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.zipkin.brave</groupId>
<artifactId>brave-core</artifactId>
<version>${brave.version}</version>
</dependency>
<dependency>
<groupId>io.zipkin.brave</groupId>
<artifactId>brave-spancollector-http</artifactId>
<version>${brave.version}</version>
</dependency>
<dependency>
<groupId>io.zipkin.brave</groupId>
<artifactId>brave-web-☛servlet-filter</artifactId>
<version>${brave.version}</version>
</dependency>
<dependency>
<groupId>io.zipkin.brave</groupId>
<artifactId>brave-apache-http-interceptors</artifactId>
<version>${brave.version}</version>
</dependency>
<dependency>
<groupId>io.zipkin.reporter</groupId>
<artifactId>zipkin-sender-okhttp3</artifactId>
<version>${zipkin.reporter.version}</version>
</dependency>
编写mvc和boot的zipkin配置类
package com.rt.platform.infosys.infoopsys.common.web.zipkin;
import com.github.kristofa.brave.Brave;
import com.github.kristofa.brave.httpclient.BraveHttpRequestInterceptor;
import com.github.kristofa.brave.httpclient.BraveHttpResponseInterceptor;
import com.github.kristofa.brave.servlet.BraveServletFilter;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import zipkin.Span;
import zipkin.reporter.AsyncReporter;
import zipkin.reporter.Reporter;
import zipkin.reporter.Sender;
import zipkin.reporter.okhttp3.OkHttpSender;
@Configuration
public class ZipConfig {
@Value("${brave.name}")
private String applicationName;
@Value("${http.sender.address}")
private String sendAddress;
/**
* Brave各工具类的封装
*
* @return Brave
*/
@Bean
public Brave brave() {
Sender sender = OkHttpSender.create(sendAddress);
Reporter<Span> reporter = AsyncReporter.builder(sender).build();
Brave brave = new Brave.Builder(applicationName).reporter(reporter).build();
return brave;
}
/**
* 拦截器,需要serverRequestInterceptor,serverResponseInterceptor 分别完成sr和ss操作
*
* @param brave
* @return
*/
@Bean
public BraveServletFilter braveServletFilter(Brave brave) {
return BraveServletFilter.create(brave);
}
/**
* httpClient客户端,需要clientRequestInterceptor,clientResponseInterceptor分别完成cs和cr操作
*
* @param brave
* @return
*/
@Bean
public CloseableHttpClient closeableHttpClient(Brave brave) {
CloseableHttpClient httpClient = HttpClients.custom()
.addInterceptorFirst(BraveHttpRequestInterceptor.create(brave))
.addInterceptorFirst(BraveHttpResponseInterceptor.create(brave))
.build();
return httpClient;
}
}
说明:
1.注入的参数为该项目的名称,以及zipkin服务的地址
2.第一个bean是配置发送到zipkin的一些参数,生成一个全局的brave;
3.第二个bean是一个filter,这里配置了对request和response的封装,主要是获取和设置traceid等的一些追踪参数;
4.第三个bean是一个配置了request和response拦截器的httpclient,以供程序内部的http调用,否则无法追踪这部分的请求;
注意:如果是mvc框架的话需要在web.xml文件里加上
<!--zipkin链路追踪-->
<filter>
<filter-name>braveServletFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<async-supported>true</async-supported>
</filter>
<filter-mapping>
<filter-name>braveServletFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
如果是boot框架的话需要在配置类里面加上
@Bean
public FilterRegistrationBean testFilterRegistration(BraveServletFilter braveServletFilter) {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(braveServletFilter);
registration.addUrlPatterns("/*");
registration.setName("braveServletFilter");
registration.setOrder(1);
return registration;
}
作用都是注册过滤器;
接下去做dubbo的集成
消费者端:
package com.rt.platform.infosys.base.common.zipkinconfig;
import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.extension.Activate;
import com.alibaba.dubbo.rpc.*;
import com.alibaba.fastjson.JSONObject;
import com.github.kristofa.brave.*;
import com.github.kristofa.brave.internal.Nullable;
import com.github.kristofa.brave.internal.Util;
import com.rt.platform.infosys.base.common.utils.BasePropertiesUtil;
import com.twitter.zipkin.gen.Span;
import zipkin.reporter.AsyncReporter;
import zipkin.reporter.Reporter;
import zipkin.reporter.Sender;
import zipkin.reporter.okhttp3.OkHttpSender;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
@Activate(group = Constants.CONSUMER)
public class DrpcClientInterceptor implements Filter {
private final ClientRequestInterceptor clientRequestInterceptor;
private final ClientResponseInterceptor clientResponseInterceptor;
private final ClientSpanThreadBinder clientSpanThreadBinder;
public DrpcClientInterceptor() {
String sendUrl = BasePropertiesUtil.getProperty(ZipkinConstants.SEND_ADDRESS);
Sender sender = OkHttpSender.create(sendUrl);
Reporter<zipkin.Span> reporter = AsyncReporter.builder(sender).build();
String application = BasePropertiesUtil.getProperty(ZipkinConstants.BRAVE_NAME);
Brave brave = new Brave.Builder(application).reporter(reporter).build();
this.clientRequestInterceptor = Util.checkNotNull(brave.clientRequestInterceptor(), null);
this.clientResponseInterceptor = Util.checkNotNull(brave.clientResponseInterceptor(), null);
this.clientSpanThreadBinder = Util.checkNotNull(brave.clientSpanThreadBinder(), null);
}
@Override
public Result invoke(Invoker<?> arg0, Invocation arg1) throws RpcException {
clientRequestInterceptor.handle(new GrpcClientRequestAdapter(arg1));
Map<String, String> att = arg1.getAttachments();
final Span currentClientSpan = clientSpanThreadBinder.getCurrentClientSpan();
Result result;
try {
result = arg0.invoke(arg1);
clientSpanThreadBinder.setCurrentSpan(currentClientSpan);
clientResponseInterceptor.handle(new GrpcClientResponseAdapter(result));
} finally {
clientSpanThreadBinder.setCurrentSpan(null);
}
return result;
}
static final class GrpcClientRequestAdapter implements ClientRequestAdapter {
private Invocation invocation;
public GrpcClientRequestAdapter(Invocation invocation) {
this.invocation = invocation;
}
@Override
public String getSpanName() {
String ls = invocation.getMethodName();
String serviceName = ls == null ? "unkown" : ls;
return serviceName;
}
@Override
public void addSpanIdToRequest(@Nullable SpanId spanId) {
Map<String, String> at = this.invocation.getAttachments();
if (spanId == null) {
at.put("Sampled", "0");
} else {
at.put("Sampled", "1");
at.put("TraceId", spanId.traceIdString());
at.put("SpanId", IdConversion.convertToString(spanId.spanId));
if (spanId.nullableParentId() != null) {
at.put("ParentSpanId", IdConversion.convertToString(spanId.parentId));
}
}
}
@Override
public Collection<KeyValueAnnotation> requestAnnotations() {
Object[] arguments = invocation.getArguments();
// Map data = ls.getData();
KeyValueAnnotation an = KeyValueAnnotation.create("params", JSONObject.toJSONString(arguments));
return Collections.singletonList(an);
}
@Override
public com.twitter.zipkin.gen.Endpoint serverAddress() {
return null;
}
}
static final class GrpcClientResponseAdapter implements ClientResponseAdapter {
private final Result result;
public GrpcClientResponseAdapter(Result result) {
this.result = result;
}
@Override
public Collection<KeyValueAnnotation> responseAnnotations() {
return Collections.<KeyValueAnnotation>emptyList();
/*
return !result.hasException()
? Collections.<KeyValueAnnotation>emptyList()
: Collections.singletonList(KeyValueAnnotation.create("error", result.getException().getMessage()));
*/
}
}
}
然后在消费者端的com.alibaba.dubbo.rpc.Filter文件里加上traceFilterc=xxx.xxx.xxx.DrpcClientInterceptor
生成端:
package com.rt.platform.infosys.base.common.zipkinconfig;
import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.extension.Activate;
import com.alibaba.dubbo.rpc.*;
import com.github.kristofa.brave.*;
import com.rt.platform.infosys.base.common.utils.BasePropertiesUtil;
import zipkin.reporter.AsyncReporter;
import zipkin.reporter.Reporter;
import zipkin.reporter.Sender;
import zipkin.reporter.okhttp3.OkHttpSender;
import java.net.SocketAddress;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import static com.github.kristofa.brave.IdConversion.convertToLong;
@Activate(group = Constants.PROVIDER)
public class DrpcServerInterceptor implements Filter {
private final ServerRequestInterceptor serverRequestInterceptor;
private final ServerResponseInterceptor serverResponseInterceptor;
public DrpcServerInterceptor() {
String sendUrl = BasePropertiesUtil.getProperty(ZipkinConstants.SEND_ADDRESS);
Sender sender = OkHttpSender.create(sendUrl);
Reporter<zipkin.Span> reporter = AsyncReporter.builder(sender).build();
String application = BasePropertiesUtil.getProperty(ZipkinConstants.BRAVE_NAME);//RpcContext.getContext().getUrl().getParameter("application");
Brave brave = new Brave.Builder(application).reporter(reporter).build();
this.serverRequestInterceptor = brave.serverRequestInterceptor();
this.serverResponseInterceptor = brave.serverResponseInterceptor();
}
@Override
public Result invoke(Invoker<?> arg0, Invocation arg1) throws RpcException {
serverRequestInterceptor.handle(new DrpcServerRequestAdapter(arg1));
Result result ;
try {
result = arg0.invoke(arg1);
serverResponseInterceptor.handle(new GrpcServerResponseAdapter(result));
} finally {
}
return result;
}
static final class DrpcServerRequestAdapter implements ServerRequestAdapter {
private Invocation invocation;
DrpcServerRequestAdapter(Invocation invocation) {
this.invocation = invocation;
}
@Override
public TraceData getTraceData() {
//Random randoml = new Random();
Map<String,String> at = this.invocation.getAttachments();
String sampled = at.get("Sampled");
String parentSpanId = at.get("ParentSpanId");
String traceId = at.get("TraceId");
String spanId = at.get("SpanId");
// 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() {
String ls = invocation.getMethodName();
String serviceName = ls == null?"unkown":ls;
return serviceName;
}
@Override
public Collection<KeyValueAnnotation> requestAnnotations() {
SocketAddress socketAddress = null;
if (socketAddress != null) {
KeyValueAnnotation remoteAddrAnnotation = KeyValueAnnotation.create(
"DRPC_REMOTE_ADDR", socketAddress.toString());
return Collections.singleton(remoteAddrAnnotation);
} else {
return Collections.emptyList();
}
}
}
static final class GrpcServerResponseAdapter implements ServerResponseAdapter {
final Result result;
public GrpcServerResponseAdapter(Result result) {
this.result = result;
}
@SuppressWarnings("unchecked")
@Override
public Collection<KeyValueAnnotation> responseAnnotations() {
return !result.hasException()
? Collections.<KeyValueAnnotation>emptyList()
: Collections.singletonList(KeyValueAnnotation.create("error", result.getException().getMessage()));
}
}
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();
}
}
然后在生产者端的com.alibaba.dubbo.rpc.Filter文件里加上traceFilters=xxx.xxx.xxx.DrpcServerInterceptor
启动项目进行接口访问,再登录zipkin服务的地址就能看到调用各个服务的情况。
网友评论