From 559b13ae2e2281d4f01ae88701e7e0fef31bcb5f Mon Sep 17 00:00:00 2001 From: conghuhu <56248584+conghuhu@users.noreply.github.com> Date: Sat, 15 Apr 2023 11:47:12 +0800 Subject: [PATCH] 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 --- .artifacts | 3 + .../apache/dubbo/config/TracingConfig.java | 16 ++ .../dubbo/config/nested/ExporterConfig.java | 79 ++++++++ .../src/main/resources/META-INF/dubbo.xsd | 42 +++++ .../dubbo-demo-spring-boot-consumer/pom.xml | 2 +- .../dubbo-demo-spring-boot-provider/pom.xml | 2 +- dubbo-distribution/dubbo-bom/pom.xml | 15 ++ .../pom.xml | 147 +++++++++++++++ ...bboMicrometerTracingAutoConfiguration.java | 9 +- .../DubboObservationAutoConfiguration.java | 12 +- .../autoconfigure/ObservabilityUtils.java | 6 +- .../ObservationHandlerGrouping.java | 0 .../ObservationRegistryPostProcessor.java | 11 +- .../ConditionalOnDubboTracingEnable.java | 15 +- .../brave/BraveAutoConfiguration.java | 27 ++- .../exporter/zipkin/HttpSender.java | 145 +++++++++++++++ .../zipkin/ZipkinAutoConfiguration.java | 60 ++++++ .../exporter/zipkin/ZipkinConfigurations.java | 171 ++++++++++++++++++ .../zipkin/ZipkinRestTemplateSender.java | 76 ++++++++ .../zipkin/ZipkinWebClientSender.java | 84 +++++++++ .../ZipkinRestTemplateBuilderCustomizer.java | 38 ++++ .../ZipkinWebClientBuilderCustomizer.java | 39 ++++ .../otel/OpenTelemetryAutoConfiguration.java | 3 +- .../main/resources/META-INF/spring.factories | 3 +- ...ot.autoconfigure.AutoConfiguration.imports | 1 + ...crometerTracingAutoConfigurationTests.java | 165 +++++++++++++++++ .../pom.xml | 49 +++++ .../pom.xml | 49 +++++ .../pom.xml | 89 ++++----- dubbo-test/dubbo-dependencies-all/pom.xml | 10 +- 30 files changed, 1269 insertions(+), 99 deletions(-) create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/config/nested/ExporterConfig.java create mode 100644 dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/pom.xml rename dubbo-spring-boot/dubbo-spring-boot-observability-starter/{ => dubbo-spring-boot-observability-autoconfigure}/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/DubboMicrometerTracingAutoConfiguration.java (94%) rename dubbo-spring-boot/dubbo-spring-boot-observability-starter/{ => dubbo-spring-boot-observability-autoconfigure}/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/DubboObservationAutoConfiguration.java (95%) rename dubbo-spring-boot/dubbo-spring-boot-observability-starter/{ => dubbo-spring-boot-observability-autoconfigure}/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservabilityUtils.java (91%) rename dubbo-spring-boot/dubbo-spring-boot-observability-starter/{ => dubbo-spring-boot-observability-autoconfigure}/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservationHandlerGrouping.java (100%) rename dubbo-spring-boot/dubbo-spring-boot-observability-starter/{ => dubbo-spring-boot-observability-autoconfigure}/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservationRegistryPostProcessor.java (87%) rename dubbo-spring-boot/dubbo-spring-boot-observability-starter/{src/main/java/org/apache/dubbo/spring/boot/observability => dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure}/annotation/ConditionalOnDubboTracingEnable.java (70%) rename dubbo-spring-boot/dubbo-spring-boot-observability-starter/{ => dubbo-spring-boot-observability-autoconfigure}/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/brave/BraveAutoConfiguration.java (88%) create mode 100644 dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/HttpSender.java create mode 100644 dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/ZipkinAutoConfiguration.java create mode 100644 dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/ZipkinConfigurations.java create mode 100644 dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/ZipkinRestTemplateSender.java create mode 100644 dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/ZipkinWebClientSender.java create mode 100644 dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/customizer/ZipkinRestTemplateBuilderCustomizer.java create mode 100644 dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/customizer/ZipkinWebClientBuilderCustomizer.java rename dubbo-spring-boot/dubbo-spring-boot-observability-starter/{ => dubbo-spring-boot-observability-autoconfigure}/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/otel/OpenTelemetryAutoConfiguration.java (99%) rename dubbo-spring-boot/dubbo-spring-boot-observability-starter/{ => dubbo-spring-boot-observability-autoconfigure}/src/main/resources/META-INF/spring.factories (77%) rename dubbo-spring-boot/dubbo-spring-boot-observability-starter/{ => dubbo-spring-boot-observability-autoconfigure}/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports (79%) create mode 100644 dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/observability/autoconfigure/observability/DubboMicrometerTracingAutoConfigurationTests.java create mode 100644 dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-tracing-brave-zipkin-starter/pom.xml create mode 100644 dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-tracing-otel-zipkin-starter/pom.xml diff --git a/.artifacts b/.artifacts index 7ad42729592..d6d687629d2 100644 --- a/.artifacts +++ b/.artifacts @@ -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 diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/TracingConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/TracingConfig.java index 62b134f35c3..3a7e4e3b917 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/config/TracingConfig.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/TracingConfig.java @@ -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 PropagationConfig getPropagation() { public void setPropagation(PropagationConfig propagation) { this.propagation = propagation; } + + public ExporterConfig getTracingExporter() { + return tracingExporter; + } + + public void setTracingExporter(ExporterConfig tracingExporter) { + this.tracingExporter = tracingExporter; + } } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/ExporterConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/ExporterConfig.java new file mode 100644 index 00000000000..076daa9287f --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/ExporterConfig.java @@ -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; + } + } +} diff --git a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd index ca5a6ec455a..8ba022c68fc 100644 --- a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd +++ b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd @@ -1210,6 +1210,7 @@ + @@ -1238,6 +1239,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2187,4 +2215,18 @@ means that these fields would end up as key-value pairs in e.g. MDC. ]]> + + + + + + + + + + + + + + diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-consumer/pom.xml b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-consumer/pom.xml index 36a26644aae..2dcd2ef3258 100644 --- a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-consumer/pom.xml +++ b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-consumer/pom.xml @@ -125,7 +125,7 @@ org.apache.dubbo - dubbo-spring-boot-observability-starter + dubbo-spring-boot-tracing-otel-zipkin-starter diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-provider/pom.xml b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-provider/pom.xml index 6df0e80c2a1..fc82ed4e837 100644 --- a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-provider/pom.xml +++ b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-provider/pom.xml @@ -120,7 +120,7 @@ org.apache.dubbo - dubbo-spring-boot-observability-starter + dubbo-spring-boot-tracing-otel-zipkin-starter diff --git a/dubbo-distribution/dubbo-bom/pom.xml b/dubbo-distribution/dubbo-bom/pom.xml index ccf5cc07b05..26aeeb9b0bc 100644 --- a/dubbo-distribution/dubbo-bom/pom.xml +++ b/dubbo-distribution/dubbo-bom/pom.xml @@ -502,6 +502,21 @@ dubbo-spring-boot-observability-starter ${project.version} + + org.apache.dubbo + dubbo-spring-boot-observability-autoconfigure + ${project.version} + + + org.apache.dubbo + dubbo-spring-boot-tracing-otel-zipkin-starter + ${project.version} + + + org.apache.dubbo + dubbo-spring-boot-tracing-brave-zipkin-starter + ${project.version} + diff --git a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/pom.xml b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/pom.xml new file mode 100644 index 00000000000..0103a93a3c1 --- /dev/null +++ b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/pom.xml @@ -0,0 +1,147 @@ + + + + + dubbo-spring-boot-observability-starter + org.apache.dubbo + ${revision} + ../pom.xml + + 4.0.0 + + dubbo-spring-boot-observability-autoconfigure + + + + + io.micrometer + micrometer-tracing + + + io.micrometer + micrometer-observation + + + io.micrometer + micrometer-core + + + io.micrometer + micrometer-registry-prometheus + + + com.tdunning + t-digest + + + + + org.springframework.boot + spring-boot-autoconfigure + true + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.springframework + spring-webmvc + true + + + org.springframework + spring-webflux + true + + + org.springframework.boot + spring-boot-test + test + + + org.assertj + assertj-core + test + + + + + io.micrometer + micrometer-tracing-bridge-otel + true + + + io.micrometer + micrometer-tracing-bridge-brave + true + + + + + io.opentelemetry + opentelemetry-exporter-zipkin + true + + + io.zipkin.reporter2 + zipkin-reporter-brave + true + + + + + io.zipkin.reporter2 + zipkin-sender-urlconnection + true + + + + + org.apache.dubbo + dubbo-spring-boot-starter + ${project.version} + + + org.apache.dubbo + dubbo-common + ${project.version} + true + + + org.apache.dubbo + dubbo-qos + ${project.version} + true + + + + + io.prometheus + simpleclient + + + io.prometheus + simpleclient_pushgateway + + + + \ No newline at end of file diff --git a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/DubboMicrometerTracingAutoConfiguration.java b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/DubboMicrometerTracingAutoConfiguration.java similarity index 94% rename from dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/DubboMicrometerTracingAutoConfiguration.java rename to dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/DubboMicrometerTracingAutoConfiguration.java index ed2553c6645..4c8adef1e32 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/DubboMicrometerTracingAutoConfiguration.java +++ b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/DubboMicrometerTracingAutoConfiguration.java @@ -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 @@ * 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; diff --git a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/DubboObservationAutoConfiguration.java b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/DubboObservationAutoConfiguration.java similarity index 95% rename from dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/DubboObservationAutoConfiguration.java rename to dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/DubboObservationAutoConfiguration.java index f87c7787a8a..37f552fadff 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/DubboObservationAutoConfiguration.java +++ b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/DubboObservationAutoConfiguration.java @@ -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 @@ static class MetricsWithTracingConfiguration { @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 @@ static class TracingAndMetricsObservationHandlerConfiguration { @Bean @ConditionalOnClass(name = {"io.micrometer.tracing.handler.TracingAwareMeterObservationHandler", "io.micrometer.tracing.Tracer"}) io.micrometer.tracing.handler.TracingAwareMeterObservationHandler 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); } diff --git a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservabilityUtils.java b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservabilityUtils.java similarity index 91% rename from dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservabilityUtils.java rename to dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservabilityUtils.java index 56ab8ec442e..bbccf44449a 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservabilityUtils.java +++ b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservabilityUtils.java @@ -26,11 +26,11 @@ */ 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"; diff --git a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservationHandlerGrouping.java b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservationHandlerGrouping.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservationHandlerGrouping.java rename to dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservationHandlerGrouping.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservationRegistryPostProcessor.java b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservationRegistryPostProcessor.java similarity index 87% rename from dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservationRegistryPostProcessor.java rename to dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservationRegistryPostProcessor.java index 47344b3f401..1d315c2b9a0 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservationRegistryPostProcessor.java +++ b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservationRegistryPostProcessor.java @@ -33,20 +33,21 @@ public class ObservationRegistryPostProcessor implements BeanPostProcessor { private final ObjectProvider> observationHandlers; public ObservationRegistryPostProcessor(ObjectProvider observationHandlerGrouping, - ObjectProvider> observationHandlers){ + ObjectProvider> 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> 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; diff --git a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/annotation/ConditionalOnDubboTracingEnable.java b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/annotation/ConditionalOnDubboTracingEnable.java similarity index 70% rename from dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/annotation/ConditionalOnDubboTracingEnable.java rename to dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/annotation/ConditionalOnDubboTracingEnable.java index 5e6d05f9ce1..eaa7d28e159 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/annotation/ConditionalOnDubboTracingEnable.java +++ b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/annotation/ConditionalOnDubboTracingEnable.java @@ -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.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 { } diff --git a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/brave/BraveAutoConfiguration.java b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/brave/BraveAutoConfiguration.java similarity index 88% rename from dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/brave/BraveAutoConfiguration.java rename to dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/brave/BraveAutoConfiguration.java index b3c0bc7f8f2..dbc6c61e001 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/brave/BraveAutoConfiguration.java +++ b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/brave/BraveAutoConfiguration.java @@ -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 @@ * 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 predicates, - ObjectProvider reporters, ObjectProvider filters) { + ObjectProvider reporters, ObjectProvider 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 spanHandlers, - List tracingCustomizers, brave.propagation.CurrentTraceContext currentTraceContext, - brave.propagation.Propagation.Factory propagationFactory, brave.sampler.Sampler sampler) { + List 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 brave.Tracer braveTracer(brave.Tracing tracing) { @Bean @ConditionalOnMissingBean public brave.propagation.CurrentTraceContext braveCurrentTraceContext(List scopeDecorators, - List currentTraceContextCustomizers) { + List 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 BraveBaggageConfiguration(DubboConfigurationProperties dubboConfigPropert brave.baggage.BaggagePropagation.FactoryBuilder b3PropagationFactoryBuilder( ObjectProvider 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 @@ brave.propagation.Propagation.Factory propagationFactory(brave.baggage.BaggagePr @ConditionalOnMissingBean brave.baggage.CorrelationScopeDecorator.Builder mdcCorrelationScopeDecoratorBuilder( ObjectProvider 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; } diff --git a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/HttpSender.java b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/HttpSender.java new file mode 100644 index 00000000000..0bc815031f9 --- /dev/null +++ b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/HttpSender.java @@ -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 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 sendSpans(List encodedSpans) { + if (this.closed) { + throw new ClosedSenderException(); + } + return sendSpans(BytesMessageEncoder.JSON.encode(encodedSpans)); + } + + abstract static class HttpPostCall extends Call.Base { + + /** + * 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(); + } + + } +} diff --git a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/ZipkinAutoConfiguration.java b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/ZipkinAutoConfiguration.java new file mode 100644 index 00000000000..237348e5484 --- /dev/null +++ b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/ZipkinAutoConfiguration.java @@ -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. + *

+ * 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 spanBytesEncoder() { + return SpanBytesEncoder.JSON_V2; + } + +} diff --git a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/ZipkinConfigurations.java b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/ZipkinConfigurations.java new file mode 100644 index 00000000000..c73fc2098ee --- /dev/null +++ b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/ZipkinConfigurations.java @@ -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 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 customizers) { + Iterable 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 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 spanReporter(Sender sender, BytesEncoder encoder) { + return AsyncReporter.builder(sender).build(encoder); + } + + } + + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(ZipkinSpanHandler.class) + static class BraveConfiguration { + + @Bean + @ConditionalOnMissingBean + @ConditionalOnBean(Reporter.class) + ZipkinSpanHandler zipkinSpanHandler(Reporter 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 encoder, ObjectProvider senders) { + AtomicReference 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(); + } + + } +} diff --git a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/ZipkinRestTemplateSender.java b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/ZipkinRestTemplateSender.java new file mode 100644 index 00000000000..45eff7f6fbe --- /dev/null +++ b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/ZipkinRestTemplateSender.java @@ -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 clone() { + return new RestTemplateHttpPostCall(this.endpoint, getUncompressedBody(), this.restTemplate); + } + + @Override + protected Void doExecute() { + HttpEntity request = new HttpEntity<>(getBody(), getDefaultHeaders()); + this.restTemplate.exchange(this.endpoint, HttpMethod.POST, request, Void.class); + return null; + } + + @Override + protected void doEnqueue(Callback callback) { + try { + doExecute(); + callback.onSuccess(null); + } catch (Exception ex) { + callback.onError(ex); + } + } + + } +} diff --git a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/ZipkinWebClientSender.java b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/ZipkinWebClientSender.java new file mode 100644 index 00000000000..128f04431a8 --- /dev/null +++ b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/ZipkinWebClientSender.java @@ -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 clone() { + return new WebClientHttpPostCall(this.endpoint, getUncompressedBody(), this.webClient); + } + + @Override + protected Void doExecute() { + sendRequest().block(); + return null; + } + + @Override + protected void doEnqueue(Callback callback) { + sendRequest().subscribe((entity) -> callback.onSuccess(null), callback::onError); + } + + private Mono> sendRequest() { + return this.webClient.post() + .uri(this.endpoint) + .headers(this::addDefaultHeaders) + .bodyValue(getBody()) + .retrieve() + .toBodilessEntity(); + } + + private void addDefaultHeaders(HttpHeaders headers) { + headers.addAll(getDefaultHeaders()); + } + + } +} diff --git a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/customizer/ZipkinRestTemplateBuilderCustomizer.java b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/customizer/ZipkinRestTemplateBuilderCustomizer.java new file mode 100644 index 00000000000..db7209e46ae --- /dev/null +++ b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/customizer/ZipkinRestTemplateBuilderCustomizer.java @@ -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); +} diff --git a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/customizer/ZipkinWebClientBuilderCustomizer.java b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/customizer/ZipkinWebClientBuilderCustomizer.java new file mode 100644 index 00000000000..d890280529c --- /dev/null +++ b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/customizer/ZipkinWebClientBuilderCustomizer.java @@ -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); + +} diff --git a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/otel/OpenTelemetryAutoConfiguration.java b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/otel/OpenTelemetryAutoConfiguration.java similarity index 99% rename from dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/otel/OpenTelemetryAutoConfiguration.java rename to dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/otel/OpenTelemetryAutoConfiguration.java index b17e2cdb47f..5652d97f0cd 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/otel/OpenTelemetryAutoConfiguration.java +++ b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/otel/OpenTelemetryAutoConfiguration.java @@ -19,9 +19,10 @@ 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; diff --git a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/resources/META-INF/spring.factories b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/resources/META-INF/spring.factories similarity index 77% rename from dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/resources/META-INF/spring.factories rename to dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/resources/META-INF/spring.factories index b7a570ea765..a42de46c097 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/resources/META-INF/spring.factories +++ b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/resources/META-INF/spring.factories @@ -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 diff --git a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports similarity index 79% rename from dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports rename to dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index 9d3769fc9c4..a9e7d12337a 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -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 \ No newline at end of file diff --git a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/observability/autoconfigure/observability/DubboMicrometerTracingAutoConfigurationTests.java b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/observability/autoconfigure/observability/DubboMicrometerTracingAutoConfigurationTests.java new file mode 100644 index 00000000000..d0e4c64b672 --- /dev/null +++ b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-observability-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/observability/autoconfigure/observability/DubboMicrometerTracingAutoConfigurationTests.java @@ -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 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); + } + + } +} diff --git a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-tracing-brave-zipkin-starter/pom.xml b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-tracing-brave-zipkin-starter/pom.xml new file mode 100644 index 00000000000..7dd89c5bf8d --- /dev/null +++ b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-tracing-brave-zipkin-starter/pom.xml @@ -0,0 +1,49 @@ + + + + + dubbo-spring-boot-observability-starter + org.apache.dubbo + ${revision} + ../pom.xml + + 4.0.0 + + dubbo-spring-boot-tracing-brave-zipkin-starter + jar + Apache Dubbo Spring Boot Tracing Brave Zipkin Starter + + + + org.apache.dubbo + dubbo-spring-boot-observability-autoconfigure + ${project.version} + + + io.micrometer + micrometer-tracing-bridge-brave + + + io.zipkin.reporter2 + zipkin-reporter-brave + + + + \ No newline at end of file diff --git a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-tracing-otel-zipkin-starter/pom.xml b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-tracing-otel-zipkin-starter/pom.xml new file mode 100644 index 00000000000..f09967097f9 --- /dev/null +++ b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/dubbo-spring-boot-tracing-otel-zipkin-starter/pom.xml @@ -0,0 +1,49 @@ + + + + + dubbo-spring-boot-observability-starter + org.apache.dubbo + ${revision} + ../pom.xml + + 4.0.0 + + dubbo-spring-boot-tracing-otel-zipkin-starter + jar + Apache Dubbo Spring Boot Tracing Otel Zipkin Starter + + + + org.apache.dubbo + dubbo-spring-boot-observability-autoconfigure + ${project.version} + + + io.micrometer + micrometer-tracing-bridge-otel + + + io.opentelemetry + opentelemetry-exporter-zipkin + + + + \ No newline at end of file diff --git a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/pom.xml b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/pom.xml index ce72ee602b0..83bf71941c7 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/pom.xml +++ b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/pom.xml @@ -25,12 +25,22 @@ ../pom.xml 4.0.0 + pom dubbo-spring-boot-observability-starter + + dubbo-spring-boot-observability-autoconfigure + dubbo-spring-boot-tracing-otel-zipkin-starter + dubbo-spring-boot-tracing-brave-zipkin-starter + + 1.10.6 1.0.3 + 1.19.0 + 2.16.3 + 0.16.0 @@ -49,65 +59,28 @@ pom import + + io.opentelemetry + opentelemetry-bom + ${opentelemetry.version} + pom + import + + + io.zipkin.reporter2 + zipkin-reporter-bom + ${zipkin-reporter.version} + pom + import + + + io.prometheus + simpleclient_bom + ${prometheus-client.version} + pom + import + - - - io.micrometer - micrometer-tracing - - - io.micrometer - micrometer-observation - - - io.micrometer - micrometer-core - - - io.micrometer - micrometer-registry-prometheus - - - io.prometheus - simpleclient_pushgateway - - - com.tdunning - t-digest - - - org.springframework.boot - spring-boot-autoconfigure - true - - - org.springframework.boot - spring-boot-configuration-processor - true - - - io.micrometer - micrometer-tracing-bridge-otel - true - - - io.micrometer - micrometer-tracing-bridge-brave - true - - - org.apache.dubbo - dubbo-spring-boot-starter - ${project.version} - - - org.apache.dubbo - dubbo-common - ${project.version} - true - - - diff --git a/dubbo-test/dubbo-dependencies-all/pom.xml b/dubbo-test/dubbo-dependencies-all/pom.xml index e085b0bd8c3..3e43c7cf368 100644 --- a/dubbo-test/dubbo-dependencies-all/pom.xml +++ b/dubbo-test/dubbo-dependencies-all/pom.xml @@ -328,7 +328,15 @@ org.apache.dubbo - dubbo-spring-boot-observability-starter + dubbo-spring-boot-observability-autoconfigure + + + org.apache.dubbo + dubbo-spring-boot-tracing-otel-zipkin-starter + + + org.apache.dubbo + dubbo-spring-boot-tracing-brave-zipkin-starter