前言
本文将从零搭建分布式链路追踪客户端工具包的Starter,并将在后续文章中逐步丰富支持的场景。这里首先将搭建一个最基础的Starter,能提供的功能和1. 看完这篇文章我奶奶都懂Opentracing了一文中的示例demo类似。
相关版本依赖如下。
opentracing-api版本:0.33.0
opentracing-spring-web版本:4.1.0
jaeger-client版本:1.8.1
Springboot版本:2.7.6
github地址:honey-tracing
正文
一. 基础Starter实现
在基础Starter中,主要是提供Servlet的过滤器和RestTemplate的拦截器,我们后续的复杂功能,就将在这个基础Starter上一点一点的丰富。
首先下图是Starter的工程结构。
在基础Starter中,Servlet的链路过滤器实现如下。
public class HoneyTracingFilter implements Filter {private final Tracer tracer;public HoneyTracingFilter(Tracer tracer) {this.tracer = tracer;}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) servletRequest;SpanContext extractedSpanContext = tracer.extract(Format.Builtin.HTTP_HEADERS,new HttpServletRequestExtractAdapter(request));Span span = tracer.buildSpan(request.getMethod()).asChildOf(extractedSpanContext).withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_SERVER).start();try (Scope scope = tracer.activateSpan(span)) {filterChain.doFilter(servletRequest, servletResponse);} catch (IOException | ServletException e) {Tags.ERROR.set(span, Boolean.TRUE);throw e;} finally {span.finish();}}}
RestTemplate的链路拦截器实现如下。
* RestTemplate客户端的分布式链路追踪拦截器。*/
public class HoneyRestTemplateTracingInterceptor implements ClientHttpRequestInterceptor {private final Tracer tracer;public HoneyRestTemplateTracingInterceptor(Tracer tracer) {this.tracer = tracer;}@NotNullpublic ClientHttpResponse intercept(@NotNull HttpRequest request, @NotNull byte[] body,ClientHttpRequestExecution execution) throws IOException {Span span = tracer.buildSpan(HONEY_REST_TEMPLATE_NAME).withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT).start();tracer.inject(span.context(), Format.Builtin.HTTP_HEADERS, new HttpHeadersCarrier(request.getHeaders()));try (Scope scope = tracer.activateSpan(span)) {return execution.execute(request, body);} catch (IOException e) {Tags.ERROR.set(span, Boolean.TRUE);throw e;} finally {span.finish();}}}
打印链路日志的HoneySpanReporter目前不打印任何日志,后面再添加打印逻辑,实现如下。
public class HoneySpanReporter implements Reporter {public void report(JaegerSpan span) {}public void close() {}}
我们使用HoneyTracingProperties来读取链路相关的配置,目前仅读取一个开关enabled,如下所示。
* 分布式链路追踪配置属性类。*/
@ConfigurationProperties("honey.tracing")
public class HoneyTracingProperties {private boolean enabled;public boolean isEnabled() {return enabled;}public void setEnabled(boolean enabled) {this.enabled = enabled;}}
使用到的一些常量,存放在CommonConstants中,如下所示。
public class CommonConstants {public static final double DEFAULT_SAMPLE_RATE = 1.0;public static final String HONEY_TRACER_NAME = "HoneyTracer";public static final String HONEY_REST_TEMPLATE_NAME = "HoneyRestTemplate";public static final String ALL_URL_PATTERN_STR = "/*";}
再接下来就是三个自动装配类,其中HoneyRestTemplateTracingConfig负责注册HoneyRestTemplateTracingInterceptor给容器中所有的RestTemplate,HoneyTracingConfig负责注册Tracer到Spring容器,HoneyTracingFilterConfig负责注册HoneyTracingFilter,实现如下所示。
* RestTemplate分布式链路追踪配置类。*/
@ConditionalOnBean(RestTemplate.class)
@Configuration
@AutoConfigureAfter(HoneyTracingConfig.class)
public class HoneyRestTemplateTracingConfig {public HoneyRestTemplateTracingConfig(List<RestTemplate> restTemplates, Tracer tracer) {for (RestTemplate restTemplate : restTemplates) {restTemplate.getInterceptors().add(new HoneyRestTemplateTracingInterceptor(tracer));}}}
* 分布式链路追踪配置类。*/
@Configuration
@EnableConfigurationProperties({HoneyTracingProperties.class})
@ConditionalOnProperty(prefix = "honey.tracing", name = "enabled", havingValue = "true", matchIfMissing = true)
public class HoneyTracingConfig {@Bean@ConditionalOnMissingBean(Sampler.class)public Sampler sampler() {return new ProbabilisticSampler(DEFAULT_SAMPLE_RATE);}@Bean@ConditionalOnMissingBean(Reporter.class)public Reporter reporter() {return new HoneySpanReporter();}@Bean@ConditionalOnMissingBean(Tracer.class)public Tracer tracer(Sampler sampler, Reporter reporter) {return new JaegerTracer.Builder(HONEY_TRACER_NAME).withTraceId128Bit().withZipkinSharedRpcSpan().withSampler(sampler).withReporter(reporter).build();}}
* Servlet过滤器配置类。*/
@Configuration
@AutoConfigureAfter(HoneyTracingConfig.class)
public class HoneyTracingFilterConfig {@Beanpublic FilterRegistrationBean<HoneyTracingFilter> honeyTracingFilter(Tracer tracer) {HoneyTracingFilter honeyTracingFilter = new HoneyTracingFilter(tracer);FilterRegistrationBean<HoneyTracingFilter> filterFilterRegistrationBean= new FilterRegistrationBean<>(honeyTracingFilter);filterFilterRegistrationBean.addUrlPatterns(ALL_URL_PATTERN_STR);return filterFilterRegistrationBean;}}
最后就是spring.factories和pom文件,内容如下所示。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.honey.tracing.config.HoneyTracingConfig,\com.honey.tracing.config.HoneyTracingFilterConfig,\com.honey.tracing.config.HoneyRestTemplateTracingConfig
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>honey-tracing</artifactId><groupId>com.honey</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>honey-starter-tracing</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId></dependency><dependency><groupId>io.opentracing</groupId><artifactId>opentracing-api</artifactId><scope>provided</scope></dependency><dependency><groupId>io.opentracing.contrib</groupId><artifactId>opentracing-spring-web</artifactId><scope>provided</scope></dependency><dependency><groupId>io.jaegertracing</groupId><artifactId>jaeger-client</artifactId><scope>provided</scope></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-source-plugin</artifactId><executions><execution><id>attach-sources</id><goals><goal>jar</goal></goals></execution></executions></plugin></plugins></build></project>
还有一点要补充,父工程的pom文件如下所示。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><packaging>pom</packaging><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.6</version></parent><groupId>com.honey</groupId><artifactId>honey-tracing</artifactId><version>1.0-SNAPSHOT</version><dependencyManagement><dependencies><dependency><groupId>io.opentracing</groupId><artifactId>opentracing-api</artifactId><version>0.33.0</version></dependency><dependency><groupId>io.opentracing.contrib</groupId><artifactId>opentracing-spring-web</artifactId><version>4.1.0</version></dependency><dependency><groupId>io.jaegertracing</groupId><artifactId>jaeger-client</artifactId><version>1.8.1</version></dependency></dependencies></dependencyManagement><modules><module>honey-starter-tracing</module><module>honey-tracing-example</module></modules></project>
二. 测试demo搭建
我们需要一个demo来测试我们的基础Starter,并且随着后续Starter支持的功能的增多,我们的demo也要相应的扩展更多的场景。
首先是demo的目录结构,如下所示。
1. example-service-1
RestTemplateConfig简单的向Spring容器注册了一个RestTemplate的bean,如下所示。
@Configuration
public class RestTemplateConfig {@Beanpublic RestTemplate restTemplate() {return new RestTemplate();}}
RestTemplateController提供了发送接口,如下所示。
@RestController
public class RestTemplateController {@Autowiredprivate RestTemplate restTemplate;@GetMapping("/send")public void send(String url) {restTemplate.getForEntity(url, Void.class);}}
最后是application.yml和pom文件,如下所示。
server:port: 8080
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>honey-tracing-example</artifactId><groupId>com.honey</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>example-service-1</artifactId><dependencies><dependency><groupId>com.honey</groupId><artifactId>honey-starter-tracing</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>io.opentracing</groupId><artifactId>opentracing-api</artifactId><version>0.33.0</version></dependency><dependency><groupId>io.opentracing.contrib</groupId><artifactId>opentracing-spring-web</artifactId><version>4.1.0</version></dependency><dependency><groupId>io.jaegertracing</groupId><artifactId>jaeger-client</artifactId><version>1.8.1</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency></dependencies></project>
2. example-service-2
RestTemplateController提供了接收接口,如下所示。
@RestController
public class RestTemplateController {@GetMapping("/receive")public void receive() {System.out.println();}}
最后是application.yml和pom文件,如下所示。
server:port: 8081
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>honey-tracing-example</artifactId><groupId>com.honey</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>example-service-2</artifactId><dependencies><dependency><groupId>com.honey</groupId><artifactId>honey-starter-tracing</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>io.opentracing</groupId><artifactId>opentracing-api</artifactId><version>0.33.0</version></dependency><dependency><groupId>io.opentracing.contrib</groupId><artifactId>opentracing-spring-web</artifactId><version>4.1.0</version></dependency><dependency><groupId>io.jaegertracing</groupId><artifactId>jaeger-client</artifactId><version>1.8.1</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency></dependencies></project>
总结
在本文,首先实现了一个基础的Starter包,为分布式链路追踪提供了Servlet过滤器和RestTemplate拦截器,其次实现了一个demo,后续分布式链路追踪Starter的功能,将用该demo完成测试。
原文:https://juejin.cn/post/7337216565097562149