4. 分布式链路追踪客户端工具包Starter设计

前言

本文将从零搭建分布式链路追踪客户端工具包的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;
    }

    @Override
    public 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;
    }

    @NotNull
    public 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给容器中所有的RestTemplateHoneyTracingConfig负责注册TracerSpring容器,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 {

    @Bean
    public 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.factoriespom文件,内容如下所示。

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容器注册了一个RestTemplatebean,如下所示。

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

}

RestTemplateController提供了发送接口,如下所示。

@RestController
public class RestTemplateController {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/send")
    public void send(String url) {
        restTemplate.getForEntity(url, Void.class);
    }

}

最后是application.ymlpom文件,如下所示。

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.ymlpom文件,如下所示。

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

相关推荐

最近更新

  1. TCP协议是安全的吗?

    2024-05-10 11:02:05       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-05-10 11:02:05       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-05-10 11:02:05       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-05-10 11:02:05       18 阅读

热门阅读

  1. Go语言系统学习笔记(二):进阶篇

    2024-05-10 11:02:05       8 阅读
  2. c#运算符重载

    2024-05-10 11:02:05       8 阅读
  3. 替换掉Springboot框架中的Tomcat,使用undertow

    2024-05-10 11:02:05       16 阅读
  4. https忽略ssl证书校验

    2024-05-10 11:02:05       9 阅读
  5. STM32 定时器最佳分频

    2024-05-10 11:02:05       9 阅读