feat: add tracing starters && add zipkin auto configuration (#12013)

* fix: fix observ-starter some bugs

* faet: add zipkin auto configuration

* fix: remove zipkin endpoint default value

* feat: add prometheus client bom to observability starter

* feat: add observability starters

* fix: add license

* feat: add observability-brave-zipkin-starter to dubbo-distribution

* fix: add moudles to dubbo-bom

* stylelint

* chore: change observ starter name

* fix
This commit is contained in:
conghuhu 2023-04-15 11:47:12 +08:00 committed by GitHub
parent 736d9965db
commit 559b13ae2e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 1269 additions and 99 deletions

View File

@ -102,6 +102,9 @@ dubbo-spring-boot-autoconfigure
dubbo-spring-boot-autoconfigure-compatible
dubbo-spring-boot-compatible
dubbo-spring-boot-observability-starter
dubbo-spring-boot-observability-autoconfigure
dubbo-spring-boot-tracing-brave-zipkin-starter
dubbo-spring-boot-tracing-otel-zipkin-starter
dubbo-spring-boot-starter
dubbo-spring-security
dubbo-xds

View File

@ -14,9 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.config;
import org.apache.dubbo.config.nested.BaggageConfig;
import org.apache.dubbo.config.nested.ExporterConfig;
import org.apache.dubbo.config.nested.PropagationConfig;
import org.apache.dubbo.config.nested.SamplingConfig;
import org.apache.dubbo.config.support.Nested;
@ -49,6 +51,12 @@ public class TracingConfig extends AbstractConfig {
@Nested
private PropagationConfig propagation = new PropagationConfig();
/**
* Exporter configuration.
*/
@Nested
private ExporterConfig tracingExporter = new ExporterConfig();
public TracingConfig() {
}
@ -87,4 +95,12 @@ public class TracingConfig extends AbstractConfig {
public void setPropagation(PropagationConfig propagation) {
this.propagation = propagation;
}
public ExporterConfig getTracingExporter() {
return tracingExporter;
}
public void setTracingExporter(ExporterConfig tracingExporter) {
this.tracingExporter = tracingExporter;
}
}

View File

@ -0,0 +1,79 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.config.nested;
import org.apache.dubbo.config.support.Nested;
import java.io.Serializable;
import java.time.Duration;
public class ExporterConfig implements Serializable {
@Nested
private ZipkinConfig zipkinConfig;
public ZipkinConfig getZipkinConfig() {
return zipkinConfig;
}
public void setZipkinConfig(ZipkinConfig zipkinConfig) {
this.zipkinConfig = zipkinConfig;
}
public static class ZipkinConfig implements Serializable {
/**
* URL to the Zipkin API.
*/
private String endpoint;
/**
* Connection timeout for requests to Zipkin.
*/
private Duration connectTimeout = Duration.ofSeconds(1);
/**
* Read timeout for requests to Zipkin.
*/
private Duration readTimeout = Duration.ofSeconds(10);
public String getEndpoint() {
return endpoint;
}
public void setEndpoint(String endpoint) {
this.endpoint = endpoint;
}
public Duration getConnectTimeout() {
return connectTimeout;
}
public void setConnectTimeout(Duration connectTimeout) {
this.connectTimeout = connectTimeout;
}
public Duration getReadTimeout() {
return readTimeout;
}
public void setReadTimeout(Duration readTimeout) {
this.readTimeout = readTimeout;
}
}
}

View File

@ -1210,6 +1210,7 @@
<xsd:complexType name="baggageType">
<xsd:all>
<xsd:element ref="remoteFields" minOccurs="0"/>
<xsd:element ref="correlation" minOccurs="0"/>
</xsd:all>
<xsd:attribute name="enabled" type="xsd:boolean">
<xsd:annotation>
@ -1238,6 +1239,33 @@
</xsd:simpleContent>
</xsd:complexType>
<xsd:complexType name="tracingExporterType">
<xsd:all>
<xsd:element ref="zipkin-config" minOccurs="0"/>
</xsd:all>
</xsd:complexType>
<xsd:complexType name="zipkinConfigType">
<xsd:attribute name="endpoint" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
<![CDATA[ The url of zipkin server. ]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="connectTimeout" type="xsd:duration">
<xsd:annotation>
<xsd:documentation>
<![CDATA[ Connection timeout for requests to Zipkin. ]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="readTimeout" type="xsd:duration">
<xsd:annotation>
<xsd:documentation>
<![CDATA[ Read timeout for requests to Zipkin. ]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
<xsd:complexType name="methodType">
<xsd:complexContent>
<xsd:extension base="abstractMethodType">
@ -2187,4 +2215,18 @@
means that these fields would end up as key-value pairs in e.g. MDC. ]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="tracing-exporter" type="tracingExporterType">
<xsd:annotation>
<xsd:documentation>
<![CDATA[ Exporter of tracing. ]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="zipkin-config" type="zipkinConfigType">
<xsd:annotation>
<xsd:documentation>
<![CDATA[ Config of zipkin exporter. ]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:schema>

View File

@ -125,7 +125,7 @@
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-observability-starter</artifactId>
<artifactId>dubbo-spring-boot-tracing-otel-zipkin-starter</artifactId>
</dependency>
<dependency>

View File

@ -120,7 +120,7 @@
<!-- Observability -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-observability-starter</artifactId>
<artifactId>dubbo-spring-boot-tracing-otel-zipkin-starter</artifactId>
</dependency>
<dependency>

View File

@ -502,6 +502,21 @@
<artifactId>dubbo-spring-boot-observability-starter</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-observability-autoconfigure</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-tracing-otel-zipkin-starter</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-tracing-brave-zipkin-starter</artifactId>
<version>${project.version}</version>
</dependency>
<!-- test -->
<dependency>

View File

@ -0,0 +1,147 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<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>dubbo-spring-boot-observability-starter</artifactId>
<groupId>org.apache.dubbo</groupId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>dubbo-spring-boot-observability-autoconfigure</artifactId>
<dependencies>
<!-- micrometer -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-observation</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<dependency>
<groupId>com.tdunning</groupId>
<artifactId>t-digest</artifactId>
</dependency>
<!-- spring -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<!-- bridge -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-otel</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-brave</artifactId>
<optional>true</optional>
</dependency>
<!-- exporter -->
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-zipkin</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.zipkin.reporter2</groupId>
<artifactId>zipkin-reporter-brave</artifactId>
<optional>true</optional>
</dependency>
<!-- sender -->
<dependency>
<groupId>io.zipkin.reporter2</groupId>
<artifactId>zipkin-sender-urlconnection</artifactId>
<optional>true</optional>
</dependency>
<!-- dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-common</artifactId>
<version>${project.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-qos</artifactId>
<version>${project.version}</version>
<optional>true</optional>
</dependency>
<!-- prometheus client -->
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient</artifactId>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient_pushgateway</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -16,7 +16,8 @@
*/
package org.apache.dubbo.spring.boot.observability.autoconfigure;
import org.apache.dubbo.spring.boot.observability.annotation.ConditionalOnDubboTracingEnable;
import org.apache.dubbo.spring.boot.observability.autoconfigure.annotation.ConditionalOnDubboTracingEnable;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@ -29,19 +30,19 @@ import org.springframework.core.annotation.Order;
* this class is available starting from Boot 3.0. It's not available if you're using Boot < 3.0
*/
@ConditionalOnDubboTracingEnable
@ConditionalOnClass(name = {"io.micrometer.observation.Observation","io.micrometer.tracing.Tracer","io.micrometer.tracing.propagation.Propagator"})
@ConditionalOnClass(name = {"io.micrometer.observation.Observation", "io.micrometer.tracing.Tracer", "io.micrometer.tracing.propagation.Propagator"})
@AutoConfigureAfter(name = "org.springframework.boot.actuate.autoconfigure.tracing.MicrometerTracingAutoConfiguration")
public class DubboMicrometerTracingAutoConfiguration {
/**
* {@code @Order} value of
* {@link #propagatingReceiverTracingObservationHandler(io.micrometer.tracing.Tracer, io.micrometer.tracing.propagation.Propagator )}.
* {@link #propagatingReceiverTracingObservationHandler(io.micrometer.tracing.Tracer, io.micrometer.tracing.propagation.Propagator)}.
*/
public static final int RECEIVER_TRACING_OBSERVATION_HANDLER_ORDER = 1000;
/**
* {@code @Order} value of
* {@link #propagatingSenderTracingObservationHandler(io.micrometer.tracing.Tracer, io.micrometer.tracing.propagation.Propagator )}.
* {@link #propagatingSenderTracingObservationHandler(io.micrometer.tracing.Tracer, io.micrometer.tracing.propagation.Propagator)}.
*/
public static final int SENDER_TRACING_OBSERVATION_HANDLER_ORDER = 2000;

View File

@ -16,21 +16,19 @@
*/
package org.apache.dubbo.spring.boot.observability.autoconfigure;
import io.micrometer.core.instrument.MeterRegistry;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.qos.protocol.QosProtocolWrapper;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.spring.boot.observability.annotation.ConditionalOnDubboTracingEnable;
import org.apache.dubbo.spring.boot.observability.autoconfigure.annotation.ConditionalOnDubboTracingEnable;
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@ -128,7 +126,7 @@ public class DubboObservationAutoConfiguration implements BeanFactoryAware, Smar
@ConditionalOnClass(name = {"io.micrometer.tracing.handler.TracingObservationHandler", "io.micrometer.core.instrument.observation.MeterObservationHandler"})
ObservationHandlerGrouping metricsAndTracingObservationHandlerGrouping() {
return new ObservationHandlerGrouping(
Arrays.asList(io.micrometer.tracing.handler.TracingObservationHandler.class, io.micrometer.core.instrument.observation.MeterObservationHandler.class));
Arrays.asList(io.micrometer.tracing.handler.TracingObservationHandler.class, io.micrometer.core.instrument.observation.MeterObservationHandler.class));
}
}
@ -157,7 +155,7 @@ public class DubboObservationAutoConfiguration implements BeanFactoryAware, Smar
@Bean
@ConditionalOnClass(name = {"io.micrometer.tracing.handler.TracingAwareMeterObservationHandler", "io.micrometer.tracing.Tracer"})
io.micrometer.tracing.handler.TracingAwareMeterObservationHandler<io.micrometer.observation.Observation.Context> tracingAwareMeterObservationHandler(
MeterRegistry meterRegistry, io.micrometer.tracing.Tracer tracer) {
MeterRegistry meterRegistry, io.micrometer.tracing.Tracer tracer) {
io.micrometer.core.instrument.observation.DefaultMeterObservationHandler delegate = new io.micrometer.core.instrument.observation.DefaultMeterObservationHandler(meterRegistry);
return new io.micrometer.tracing.handler.TracingAwareMeterObservationHandler<>(delegate, tracer);
}

View File

@ -26,11 +26,11 @@ import static org.apache.dubbo.spring.boot.util.DubboUtils.PROPERTY_NAME_SEPARAT
*/
public class ObservabilityUtils {
public static final String DUBBO_TRACING_PREFIX = DUBBO_PREFIX + PROPERTY_NAME_SEPARATOR + "tracing" + PROPERTY_NAME_SEPARATOR;
public static final String DUBBO_TRACING_PREFIX = DUBBO_PREFIX + PROPERTY_NAME_SEPARATOR + "tracing";
public static final String DUBBO_TRACING_PROPAGATION = DUBBO_TRACING_PREFIX + "propagation";
public static final String DUBBO_TRACING_PROPAGATION = DUBBO_TRACING_PREFIX + PROPERTY_NAME_SEPARATOR + "propagation";
public static final String DUBBO_TRACING_BAGGAGE = DUBBO_TRACING_PREFIX + "baggage";
public static final String DUBBO_TRACING_BAGGAGE = DUBBO_TRACING_PREFIX + PROPERTY_NAME_SEPARATOR + "baggage";
public static final String DUBBO_TRACING_BAGGAGE_CORRELATION = DUBBO_TRACING_BAGGAGE + PROPERTY_NAME_SEPARATOR + "correlation";

View File

@ -33,20 +33,21 @@ public class ObservationRegistryPostProcessor implements BeanPostProcessor {
private final ObjectProvider<ObservationHandler<?>> observationHandlers;
public ObservationRegistryPostProcessor(ObjectProvider<ObservationHandlerGrouping> observationHandlerGrouping,
ObjectProvider<ObservationHandler<?>> observationHandlers){
ObjectProvider<ObservationHandler<?>> observationHandlers) {
this.observationHandlerGrouping = observationHandlerGrouping;
this.observationHandlers = observationHandlers;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof ObservationRegistry){
if (bean instanceof ObservationRegistry) {
ObservationRegistry observationRegistry = (ObservationRegistry) bean;
List<ObservationHandler<?>> observationHandlerList =
observationHandlers.orderedStream().collect(Collectors.toList());
observationHandlerGrouping.ifAvailable(grouping->{
observationHandlers.orderedStream().collect(Collectors.toList());
observationHandlerGrouping.ifAvailable(grouping -> {
grouping.apply(observationHandlerList,
observationRegistry.observationConfig());
observationRegistry.observationConfig());
});
}
return bean;

View File

@ -14,7 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.spring.boot.observability.annotation;
package org.apache.dubbo.spring.boot.observability.autoconfigure.annotation;
import org.apache.dubbo.spring.boot.observability.autoconfigure.ObservabilityUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@ -25,10 +27,17 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE,ElementType.METHOD})
/**
* Checks whether tracing is enabled.
* It matches if the value of the {@code dubbo.tracing.enabled} property is {@code true} or if it
* is not configured.
*
* @since 3.2.0
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@ConditionalOnProperty(prefix = "dubbo.tracing", name = "enabled", matchIfMissing = true)
@ConditionalOnProperty(prefix = ObservabilityUtils.DUBBO_TRACING_PREFIX, name = "enabled", matchIfMissing = true)
public @interface ConditionalOnDubboTracingEnable {
}

View File

@ -16,12 +16,11 @@
*/
package org.apache.dubbo.spring.boot.observability.autoconfigure.brave;
import org.apache.dubbo.spring.boot.autoconfigure.DubboConfigurationProperties;
import org.apache.dubbo.spring.boot.observability.annotation.ConditionalOnDubboTracingEnable;
import org.apache.dubbo.spring.boot.observability.autoconfigure.DubboMicrometerTracingAutoConfiguration;
import org.apache.dubbo.spring.boot.observability.autoconfigure.ObservabilityUtils;
import org.apache.dubbo.spring.boot.observability.autoconfigure.annotation.ConditionalOnDubboTracingEnable;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@ -43,7 +42,7 @@ import java.util.stream.Collectors;
* provider Brave when you are using Boot <3.0 or you are not using spring-boot-starter-actuator
*/
@AutoConfiguration(before = DubboMicrometerTracingAutoConfiguration.class, afterName = "org.springframework.boot.actuate.autoconfigure.tracing.BraveAutoConfiguration")
@ConditionalOnClass(name={"io.micrometer.tracing.Tracer", "io.micrometer.tracing.brave.bridge.BraveTracer","io.micrometer.tracing.brave.bridge.BraveBaggageManager","brave.Tracing"})
@ConditionalOnClass(name = {"io.micrometer.tracing.Tracer", "io.micrometer.tracing.brave.bridge.BraveTracer", "io.micrometer.tracing.brave.bridge.BraveBaggageManager", "brave.Tracing"})
@EnableConfigurationProperties(DubboConfigurationProperties.class)
@ConditionalOnDubboTracingEnable
public class BraveAutoConfiguration {
@ -59,21 +58,21 @@ public class BraveAutoConfiguration {
@ConditionalOnMissingBean
@Order(Ordered.HIGHEST_PRECEDENCE)
io.micrometer.tracing.brave.bridge.CompositeSpanHandler compositeSpanHandler(ObjectProvider<io.micrometer.tracing.exporter.SpanExportingPredicate> predicates,
ObjectProvider<io.micrometer.tracing.exporter.SpanReporter> reporters, ObjectProvider<io.micrometer.tracing.exporter.SpanFilter> filters) {
ObjectProvider<io.micrometer.tracing.exporter.SpanReporter> reporters, ObjectProvider<io.micrometer.tracing.exporter.SpanFilter> filters) {
return new io.micrometer.tracing.brave.bridge.CompositeSpanHandler(predicates.orderedStream().collect(Collectors.toList()),
reporters.orderedStream().collect(Collectors.toList()),
filters.orderedStream().collect(Collectors.toList()));
reporters.orderedStream().collect(Collectors.toList()),
filters.orderedStream().collect(Collectors.toList()));
}
@Bean
@ConditionalOnMissingBean
public brave.Tracing braveTracing(Environment environment, List<brave.handler.SpanHandler> spanHandlers,
List<brave.TracingCustomizer> tracingCustomizers, brave.propagation.CurrentTraceContext currentTraceContext,
brave.propagation.Propagation.Factory propagationFactory, brave.sampler.Sampler sampler) {
List<brave.TracingCustomizer> tracingCustomizers, brave.propagation.CurrentTraceContext currentTraceContext,
brave.propagation.Propagation.Factory propagationFactory, brave.sampler.Sampler sampler) {
String applicationName = environment.getProperty("spring.application.name", DEFAULT_APPLICATION_NAME);
brave.Tracing.Builder builder = brave.Tracing.newBuilder().currentTraceContext(currentTraceContext).traceId128Bit(true)
.supportsJoin(false).propagationFactory(propagationFactory).sampler(sampler)
.localServiceName(applicationName);
.supportsJoin(false).propagationFactory(propagationFactory).sampler(sampler)
.localServiceName(applicationName);
spanHandlers.forEach(builder::addSpanHandler);
for (brave.TracingCustomizer tracingCustomizer : tracingCustomizers) {
tracingCustomizer.customize(builder);
@ -90,7 +89,7 @@ public class BraveAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public brave.propagation.CurrentTraceContext braveCurrentTraceContext(List<brave.propagation.CurrentTraceContext.ScopeDecorator> scopeDecorators,
List<brave.propagation.CurrentTraceContextCustomizer> currentTraceContextCustomizers) {
List<brave.propagation.CurrentTraceContextCustomizer> currentTraceContextCustomizers) {
brave.propagation.ThreadLocalCurrentTraceContext.Builder builder = brave.propagation.ThreadLocalCurrentTraceContext.newBuilder();
scopeDecorators.forEach(builder::addScopeDecorator);
for (brave.propagation.CurrentTraceContextCustomizer currentTraceContextCustomizer : currentTraceContextCustomizers) {
@ -164,7 +163,7 @@ public class BraveAutoConfiguration {
brave.baggage.BaggagePropagation.FactoryBuilder b3PropagationFactoryBuilder(
ObjectProvider<brave.baggage.BaggagePropagationCustomizer> baggagePropagationCustomizers) {
brave.propagation.Propagation.Factory delegate =
brave.propagation.B3Propagation.newFactoryBuilder().injectFormat(brave.propagation.B3Propagation.Format.SINGLE_NO_PARENT).build();
brave.propagation.B3Propagation.newFactoryBuilder().injectFormat(brave.propagation.B3Propagation.Format.SINGLE_NO_PARENT).build();
brave.baggage.BaggagePropagation.FactoryBuilder builder = brave.baggage.BaggagePropagation.newFactoryBuilder(delegate);
baggagePropagationCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
@ -205,7 +204,7 @@ public class BraveAutoConfiguration {
@ConditionalOnMissingBean
brave.baggage.CorrelationScopeDecorator.Builder mdcCorrelationScopeDecoratorBuilder(
ObjectProvider<brave.baggage.CorrelationScopeCustomizer> correlationScopeCustomizers) {
brave.baggage.CorrelationScopeDecorator.Builder builder = brave.context.slf4j.MDCScopeDecorator.newBuilder();
brave.baggage.CorrelationScopeDecorator.Builder builder = brave.context.slf4j.MDCScopeDecorator.newBuilder();
correlationScopeCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
return builder;
}

View File

@ -0,0 +1,145 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.zipkin;
import org.springframework.http.HttpHeaders;
import org.springframework.util.unit.DataSize;
import zipkin2.Call;
import zipkin2.CheckResult;
import zipkin2.codec.Encoding;
import zipkin2.reporter.BytesMessageEncoder;
import zipkin2.reporter.ClosedSenderException;
import zipkin2.reporter.Sender;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.Collections;
import java.util.List;
import java.util.zip.GZIPOutputStream;
/**
* A Zipkin {@link Sender} that uses an HTTP client to send JSON spans. Supports automatic compression with gzip.
*/
abstract class HttpSender extends Sender {
private static final DataSize MESSAGE_MAX_SIZE = DataSize.ofKilobytes(512);
private volatile boolean closed;
@Override
public Encoding encoding() {
return Encoding.JSON;
}
@Override
public int messageMaxBytes() {
return (int) MESSAGE_MAX_SIZE.toBytes();
}
@Override
public int messageSizeInBytes(List<byte[]> encodedSpans) {
return encoding().listSizeInBytes(encodedSpans);
}
@Override
public int messageSizeInBytes(int encodedSizeInBytes) {
return encoding().listSizeInBytes(encodedSizeInBytes);
}
@Override
public CheckResult check() {
try {
sendSpans(Collections.emptyList()).execute();
return CheckResult.OK;
} catch (IOException | RuntimeException ex) {
return CheckResult.failed(ex);
}
}
@Override
public void close() throws IOException {
this.closed = true;
}
/**
* The returned {@link HttpPostCall} will send span(s) as a POST to a zipkin endpoint
* when executed.
*
* @param batchedEncodedSpans list of encoded spans as a byte array
* @return an instance of a Zipkin {@link Call} which can be executed
*/
protected abstract HttpPostCall sendSpans(byte[] batchedEncodedSpans);
@Override
public Call<Void> sendSpans(List<byte[]> encodedSpans) {
if (this.closed) {
throw new ClosedSenderException();
}
return sendSpans(BytesMessageEncoder.JSON.encode(encodedSpans));
}
abstract static class HttpPostCall extends Call.Base<Void> {
/**
* Only use gzip compression on data which is bigger than this in bytes.
*/
private static final DataSize COMPRESSION_THRESHOLD = DataSize.ofKilobytes(1);
private final byte[] body;
HttpPostCall(byte[] body) {
this.body = body;
}
protected byte[] getBody() {
if (needsCompression()) {
return compress(this.body);
}
return this.body;
}
protected byte[] getUncompressedBody() {
return this.body;
}
protected HttpHeaders getDefaultHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.set("b3", "0");
headers.set("Content-Type", "application/json");
if (needsCompression()) {
headers.set("Content-Encoding", "gzip");
}
return headers;
}
private boolean needsCompression() {
return this.body.length > COMPRESSION_THRESHOLD.toBytes();
}
private byte[] compress(byte[] input) {
ByteArrayOutputStream result = new ByteArrayOutputStream();
try (GZIPOutputStream gzip = new GZIPOutputStream(result)) {
gzip.write(input);
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
return result.toByteArray();
}
}
}

View File

@ -0,0 +1,60 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.zipkin;
import org.apache.dubbo.spring.boot.observability.autoconfigure.annotation.ConditionalOnDubboTracingEnable;
import org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.zipkin.ZipkinConfigurations.BraveConfiguration;
import org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.zipkin.ZipkinConfigurations.OpenTelemetryConfiguration;
import org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.zipkin.ZipkinConfigurations.ReporterConfiguration;
import org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.zipkin.ZipkinConfigurations.SenderConfiguration;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import zipkin2.Span;
import zipkin2.codec.BytesEncoder;
import zipkin2.codec.SpanBytesEncoder;
import zipkin2.reporter.Sender;
/**
* {@link EnableAutoConfiguration Auto-configuration} for Zipkin.
* <p>
* It uses imports on {@link ZipkinConfigurations} to guarantee the correct configuration ordering.
*
* @since 3.2.0
*/
@AutoConfiguration(after = RestTemplateAutoConfiguration.class)
@ConditionalOnClass(Sender.class)
@Import({SenderConfiguration.class,
ReporterConfiguration.class, BraveConfiguration.class,
OpenTelemetryConfiguration.class})
@ConditionalOnDubboTracingEnable
public class ZipkinAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public BytesEncoder<Span> spanBytesEncoder() {
return SpanBytesEncoder.JSON_V2;
}
}

View File

@ -0,0 +1,171 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.zipkin;
import org.apache.dubbo.config.nested.ExporterConfig;
import org.apache.dubbo.spring.boot.autoconfigure.DubboConfigurationProperties;
import org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.zipkin.customizer.ZipkinRestTemplateBuilderCustomizer;
import org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.zipkin.customizer.ZipkinWebClientBuilderCustomizer;
import io.opentelemetry.exporter.zipkin.ZipkinSpanExporter;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.client.WebClient;
import zipkin2.Span;
import zipkin2.codec.BytesEncoder;
import zipkin2.reporter.AsyncReporter;
import zipkin2.reporter.Reporter;
import zipkin2.reporter.Sender;
import zipkin2.reporter.brave.ZipkinSpanHandler;
import zipkin2.reporter.urlconnection.URLConnectionSender;
import java.util.concurrent.atomic.AtomicReference;
/**
* Configurations for Zipkin. Those are imported by {@link ZipkinAutoConfiguration}.
*/
class ZipkinConfigurations {
@Configuration(proxyBeanMethods = false)
@Import({UrlConnectionSenderConfiguration.class, WebClientSenderConfiguration.class,
RestTemplateSenderConfiguration.class})
static class SenderConfiguration {
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(URLConnectionSender.class)
@EnableConfigurationProperties(DubboConfigurationProperties.class)
static class UrlConnectionSenderConfiguration {
@Bean
@ConditionalOnMissingBean(Sender.class)
URLConnectionSender urlConnectionSender(DubboConfigurationProperties properties) {
URLConnectionSender.Builder builder = URLConnectionSender.newBuilder();
ExporterConfig.ZipkinConfig zipkinConfig = properties.getTracing().getTracingExporter().getZipkinConfig();
builder.connectTimeout((int) zipkinConfig.getConnectTimeout().toMillis());
builder.readTimeout((int) zipkinConfig.getReadTimeout().toMillis());
builder.endpoint(zipkinConfig.getEndpoint());
return builder.build();
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RestTemplate.class)
@EnableConfigurationProperties(DubboConfigurationProperties.class)
static class RestTemplateSenderConfiguration {
@Bean
@ConditionalOnMissingBean(Sender.class)
ZipkinRestTemplateSender restTemplateSender(DubboConfigurationProperties properties,
ObjectProvider<ZipkinRestTemplateBuilderCustomizer> customizers) {
ExporterConfig.ZipkinConfig zipkinConfig = properties.getTracing().getTracingExporter().getZipkinConfig();
RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder()
.setConnectTimeout(zipkinConfig.getConnectTimeout())
.setReadTimeout(zipkinConfig.getReadTimeout());
restTemplateBuilder = applyCustomizers(restTemplateBuilder, customizers);
return new ZipkinRestTemplateSender(zipkinConfig.getEndpoint(), restTemplateBuilder.build());
}
private RestTemplateBuilder applyCustomizers(RestTemplateBuilder restTemplateBuilder,
ObjectProvider<ZipkinRestTemplateBuilderCustomizer> customizers) {
Iterable<ZipkinRestTemplateBuilderCustomizer> orderedCustomizers = () -> customizers.orderedStream()
.iterator();
RestTemplateBuilder currentBuilder = restTemplateBuilder;
for (ZipkinRestTemplateBuilderCustomizer customizer : orderedCustomizers) {
currentBuilder = customizer.customize(currentBuilder);
}
return currentBuilder;
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(WebClient.class)
@EnableConfigurationProperties(DubboConfigurationProperties.class)
static class WebClientSenderConfiguration {
@Bean
@ConditionalOnMissingBean(Sender.class)
ZipkinWebClientSender webClientSender(DubboConfigurationProperties properties,
ObjectProvider<ZipkinWebClientBuilderCustomizer> customizers) {
ExporterConfig.ZipkinConfig zipkinConfig = properties.getTracing().getTracingExporter().getZipkinConfig();
WebClient.Builder builder = WebClient.builder();
customizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
return new ZipkinWebClientSender(zipkinConfig.getEndpoint(), builder.build());
}
}
@Configuration(proxyBeanMethods = false)
static class ReporterConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(Sender.class)
AsyncReporter<Span> spanReporter(Sender sender, BytesEncoder<Span> encoder) {
return AsyncReporter.builder(sender).build(encoder);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ZipkinSpanHandler.class)
static class BraveConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(Reporter.class)
ZipkinSpanHandler zipkinSpanHandler(Reporter<Span> spanReporter) {
return (ZipkinSpanHandler) ZipkinSpanHandler.newBuilder(spanReporter).build();
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ZipkinSpanExporter.class)
@EnableConfigurationProperties(DubboConfigurationProperties.class)
static class OpenTelemetryConfiguration {
@Bean
@ConditionalOnMissingBean
ZipkinSpanExporter zipkinSpanExporter(DubboConfigurationProperties properties, BytesEncoder<Span> encoder, ObjectProvider<Sender> senders) {
AtomicReference<Sender> senderRef = new AtomicReference<>();
senders.orderedStream().findFirst().ifPresent(senderRef::set);
Sender sender = senderRef.get();
if (sender == null) {
ExporterConfig.ZipkinConfig zipkinConfig = properties.getTracing().getTracingExporter().getZipkinConfig();
return ZipkinSpanExporter.builder()
.setEncoder(encoder)
.setEndpoint(zipkinConfig.getEndpoint())
.setReadTimeout(zipkinConfig.getReadTimeout())
.build();
}
return ZipkinSpanExporter.builder().setEncoder(encoder).setSender(sender).build();
}
}
}

View File

@ -0,0 +1,76 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.zipkin;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.web.client.RestTemplate;
import zipkin2.Call;
import zipkin2.Callback;
class ZipkinRestTemplateSender extends HttpSender {
private final String endpoint;
private final RestTemplate restTemplate;
ZipkinRestTemplateSender(String endpoint, RestTemplate restTemplate) {
this.endpoint = endpoint;
this.restTemplate = restTemplate;
}
@Override
public HttpPostCall sendSpans(byte[] batchedEncodedSpans) {
return new RestTemplateHttpPostCall(this.endpoint, batchedEncodedSpans, this.restTemplate);
}
private static class RestTemplateHttpPostCall extends HttpPostCall {
private final String endpoint;
private final RestTemplate restTemplate;
RestTemplateHttpPostCall(String endpoint, byte[] body, RestTemplate restTemplate) {
super(body);
this.endpoint = endpoint;
this.restTemplate = restTemplate;
}
@Override
public Call<Void> clone() {
return new RestTemplateHttpPostCall(this.endpoint, getUncompressedBody(), this.restTemplate);
}
@Override
protected Void doExecute() {
HttpEntity<byte[]> request = new HttpEntity<>(getBody(), getDefaultHeaders());
this.restTemplate.exchange(this.endpoint, HttpMethod.POST, request, Void.class);
return null;
}
@Override
protected void doEnqueue(Callback<Void> callback) {
try {
doExecute();
callback.onSuccess(null);
} catch (Exception ex) {
callback.onError(ex);
}
}
}
}

View File

@ -0,0 +1,84 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.zipkin;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import zipkin2.Call;
import zipkin2.Callback;
class ZipkinWebClientSender extends HttpSender {
private final String endpoint;
private final WebClient webClient;
ZipkinWebClientSender(String endpoint, WebClient webClient) {
this.endpoint = endpoint;
this.webClient = webClient;
}
@Override
public HttpPostCall sendSpans(byte[] batchedEncodedSpans) {
return new WebClientHttpPostCall(this.endpoint, batchedEncodedSpans, this.webClient);
}
private static class WebClientHttpPostCall extends HttpPostCall {
private final String endpoint;
private final WebClient webClient;
WebClientHttpPostCall(String endpoint, byte[] body, WebClient webClient) {
super(body);
this.endpoint = endpoint;
this.webClient = webClient;
}
@Override
public Call<Void> clone() {
return new WebClientHttpPostCall(this.endpoint, getUncompressedBody(), this.webClient);
}
@Override
protected Void doExecute() {
sendRequest().block();
return null;
}
@Override
protected void doEnqueue(Callback<Void> callback) {
sendRequest().subscribe((entity) -> callback.onSuccess(null), callback::onError);
}
private Mono<ResponseEntity<Void>> sendRequest() {
return this.webClient.post()
.uri(this.endpoint)
.headers(this::addDefaultHeaders)
.bodyValue(getBody())
.retrieve()
.toBodilessEntity();
}
private void addDefaultHeaders(HttpHeaders headers) {
headers.addAll(getDefaultHeaders());
}
}
}

View File

@ -0,0 +1,38 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.zipkin.customizer;
import org.springframework.boot.web.client.RestTemplateBuilder;
/**
* Callback interface that can be implemented by beans wishing to customize the
* {@link RestTemplateBuilder} used to send spans to Zipkin.
*
* @since 3.2.0
*/
@FunctionalInterface
public interface ZipkinRestTemplateBuilderCustomizer {
/**
* Customize the rest template builder.
*
* @param restTemplateBuilder the {@code RestTemplateBuilder} to customize
* @return the customized {@code RestTemplateBuilder}
*/
RestTemplateBuilder customize(RestTemplateBuilder restTemplateBuilder);
}

View File

@ -0,0 +1,39 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.zipkin.customizer;
import org.springframework.web.reactive.function.client.WebClient;
/**
* Callback interface that can be implemented by beans wishing to customize the
* {@link WebClient.Builder} used to send spans to Zipkin.
*
* @since 3.2.0
*/
@FunctionalInterface
public interface ZipkinWebClientBuilderCustomizer {
/**
* Customize the web client builder.
*
* @param webClientBuilder the {@code WebClient.Builder} to customize
*/
void customize(WebClient.Builder webClientBuilder);
}

View File

@ -19,9 +19,10 @@ package org.apache.dubbo.spring.boot.observability.autoconfigure.otel;
import org.apache.dubbo.common.Version;
import org.apache.dubbo.spring.boot.autoconfigure.DubboConfigurationProperties;
import org.apache.dubbo.spring.boot.observability.annotation.ConditionalOnDubboTracingEnable;
import org.apache.dubbo.spring.boot.observability.autoconfigure.annotation.ConditionalOnDubboTracingEnable ;
import org.apache.dubbo.spring.boot.observability.autoconfigure.DubboMicrometerTracingAutoConfiguration;
import org.apache.dubbo.spring.boot.observability.autoconfigure.ObservabilityUtils;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;

View File

@ -2,5 +2,6 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.apache.dubbo.spring.boot.observability.autoconfigure.otel.OpenTelemetryAutoConfiguration,\
org.apache.dubbo.spring.boot.observability.autoconfigure.DubboMicrometerTracingAutoConfiguration,\
org.apache.dubbo.spring.boot.observability.autoconfigure.DubboObservationAutoConfiguration,\
org.apache.dubbo.spring.boot.observability.autoconfigure.brave.BraveAutoConfiguration
org.apache.dubbo.spring.boot.observability.autoconfigure.brave.BraveAutoConfiguration,\
org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.zipkin.ZipkinAutoConfiguration

View File

@ -2,3 +2,4 @@ org.apache.dubbo.spring.boot.observability.autoconfigure.otel.OpenTelemetryAutoC
org.apache.dubbo.spring.boot.observability.autoconfigure.DubboMicrometerTracingAutoConfiguration
org.apache.dubbo.spring.boot.observability.autoconfigure.DubboObservationAutoConfiguration
org.apache.dubbo.spring.boot.observability.autoconfigure.brave.BraveAutoConfiguration
org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.zipkin.ZipkinAutoConfiguration

View File

@ -0,0 +1,165 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.spring.boot.observability.autoconfigure.observability;
import org.apache.dubbo.spring.boot.observability.autoconfigure.DubboMicrometerTracingAutoConfiguration;
import io.micrometer.tracing.Tracer;
import io.micrometer.tracing.handler.DefaultTracingObservationHandler;
import io.micrometer.tracing.handler.PropagatingReceiverTracingObservationHandler;
import io.micrometer.tracing.handler.PropagatingSenderTracingObservationHandler;
import io.micrometer.tracing.handler.TracingObservationHandler;
import io.micrometer.tracing.propagation.Propagator;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link DubboMicrometerTracingAutoConfiguration}
*/
class DubboMicrometerTracingAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(DubboMicrometerTracingAutoConfiguration.class));
@Test
void shouldSupplyBeans() {
this.contextRunner.withUserConfiguration(TracerConfiguration.class, PropagatorConfiguration.class)
.run((context) -> {
assertThat(context).hasSingleBean(DefaultTracingObservationHandler.class);
assertThat(context).hasSingleBean(PropagatingReceiverTracingObservationHandler.class);
assertThat(context).hasSingleBean(PropagatingSenderTracingObservationHandler.class);
});
}
@Test
@SuppressWarnings("rawtypes")
void shouldSupplyBeansInCorrectOrder() {
this.contextRunner.withUserConfiguration(TracerConfiguration.class, PropagatorConfiguration.class)
.run((context) -> {
List<TracingObservationHandler> tracingObservationHandlers = context
.getBeanProvider(TracingObservationHandler.class)
.orderedStream()
.collect(Collectors.toList());
assertThat(tracingObservationHandlers).hasSize(3);
assertThat(tracingObservationHandlers.get(0))
.isInstanceOf(PropagatingReceiverTracingObservationHandler.class);
assertThat(tracingObservationHandlers.get(1))
.isInstanceOf(PropagatingSenderTracingObservationHandler.class);
assertThat(tracingObservationHandlers.get(2)).isInstanceOf(DefaultTracingObservationHandler.class);
});
}
@Test
void shouldBackOffOnCustomBeans() {
this.contextRunner.withUserConfiguration(CustomConfiguration.class).run((context) -> {
assertThat(context).hasBean("customDefaultTracingObservationHandler");
assertThat(context).hasSingleBean(DefaultTracingObservationHandler.class);
assertThat(context).hasBean("customPropagatingReceiverTracingObservationHandler");
assertThat(context).hasSingleBean(PropagatingReceiverTracingObservationHandler.class);
assertThat(context).hasBean("customPropagatingSenderTracingObservationHandler");
assertThat(context).hasSingleBean(PropagatingSenderTracingObservationHandler.class);
});
}
@Test
void shouldNotSupplyBeansIfMicrometerIsMissing() {
this.contextRunner.withClassLoader(new FilteredClassLoader("io.micrometer")).run((context) -> {
assertThat(context).doesNotHaveBean(DefaultTracingObservationHandler.class);
assertThat(context).doesNotHaveBean(PropagatingReceiverTracingObservationHandler.class);
assertThat(context).doesNotHaveBean(PropagatingSenderTracingObservationHandler.class);
});
}
@Test
void shouldNotSupplyBeansIfTracerIsMissing() {
this.contextRunner.withUserConfiguration(PropagatorConfiguration.class).run((context) -> {
assertThat(context).doesNotHaveBean(DefaultTracingObservationHandler.class);
assertThat(context).doesNotHaveBean(PropagatingReceiverTracingObservationHandler.class);
assertThat(context).doesNotHaveBean(PropagatingSenderTracingObservationHandler.class);
});
}
@Test
void shouldNotSupplyBeansIfPropagatorIsMissing() {
this.contextRunner.withUserConfiguration(TracerConfiguration.class).run((context) -> {
assertThat(context).doesNotHaveBean(PropagatingSenderTracingObservationHandler.class);
assertThat(context).doesNotHaveBean(PropagatingReceiverTracingObservationHandler.class);
});
}
@Test
void shouldNotSupplyBeansIfTracingIsDisabled() {
this.contextRunner.withUserConfiguration(TracerConfiguration.class, PropagatorConfiguration.class)
.withPropertyValues("dubbo.tracing.enabled=false")
.run((context) -> {
assertThat(context).doesNotHaveBean(DefaultTracingObservationHandler.class);
assertThat(context).doesNotHaveBean(PropagatingReceiverTracingObservationHandler.class);
assertThat(context).doesNotHaveBean(PropagatingSenderTracingObservationHandler.class);
});
}
@Configuration(proxyBeanMethods = false)
private static class TracerConfiguration {
@Bean
Tracer tracer() {
return mock(Tracer.class);
}
}
@Configuration(proxyBeanMethods = false)
private static class PropagatorConfiguration {
@Bean
Propagator propagator() {
return mock(Propagator.class);
}
}
@Configuration(proxyBeanMethods = false)
private static class CustomConfiguration {
@Bean
DefaultTracingObservationHandler customDefaultTracingObservationHandler() {
return mock(DefaultTracingObservationHandler.class);
}
@Bean
PropagatingReceiverTracingObservationHandler<?> customPropagatingReceiverTracingObservationHandler() {
return mock(PropagatingReceiverTracingObservationHandler.class);
}
@Bean
PropagatingSenderTracingObservationHandler<?> customPropagatingSenderTracingObservationHandler() {
return mock(PropagatingSenderTracingObservationHandler.class);
}
}
}

View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<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>dubbo-spring-boot-observability-starter</artifactId>
<groupId>org.apache.dubbo</groupId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>dubbo-spring-boot-tracing-brave-zipkin-starter</artifactId>
<packaging>jar</packaging>
<description>Apache Dubbo Spring Boot Tracing Brave Zipkin Starter</description>
<dependencies>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-observability-autoconfigure</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-brave</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.reporter2</groupId>
<artifactId>zipkin-reporter-brave</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<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>dubbo-spring-boot-observability-starter</artifactId>
<groupId>org.apache.dubbo</groupId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>dubbo-spring-boot-tracing-otel-zipkin-starter</artifactId>
<packaging>jar</packaging>
<description>Apache Dubbo Spring Boot Tracing Otel Zipkin Starter</description>
<dependencies>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-observability-autoconfigure</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-otel</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-zipkin</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -25,12 +25,22 @@
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<artifactId>dubbo-spring-boot-observability-starter</artifactId>
<modules>
<module>dubbo-spring-boot-observability-autoconfigure</module>
<module>dubbo-spring-boot-tracing-otel-zipkin-starter</module>
<module>dubbo-spring-boot-tracing-brave-zipkin-starter</module>
</modules>
<properties>
<micrometer.version>1.10.6</micrometer.version>
<micrometer-tracing.version>1.0.3</micrometer-tracing.version>
<opentelemetry.version>1.19.0</opentelemetry.version>
<zipkin-reporter.version>2.16.3</zipkin-reporter.version>
<prometheus-client.version>0.16.0</prometheus-client.version>
</properties>
<dependencyManagement>
@ -49,65 +59,28 @@
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-bom</artifactId>
<version>${opentelemetry.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>io.zipkin.reporter2</groupId>
<artifactId>zipkin-reporter-bom</artifactId>
<version>${zipkin-reporter.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient_bom</artifactId>
<version>${prometheus-client.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-observation</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient_pushgateway</artifactId>
</dependency>
<dependency>
<groupId>com.tdunning</groupId>
<artifactId>t-digest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-otel</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-brave</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-common</artifactId>
<version>${project.version}</version>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@ -328,7 +328,15 @@
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-observability-starter</artifactId>
<artifactId>dubbo-spring-boot-observability-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-tracing-otel-zipkin-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-tracing-brave-zipkin-starter</artifactId>
</dependency>
<!-- test -->