This is an automated email from the ASF dual-hosted git repository.
albumenj pushed a commit to branch 3.2
in repository https://gitbox.apache.org/repos/asf/dubbo.git
The following commit(s) were added to refs/heads/3.2 by this push:
new 34981c9606 add dubbo-spring-boot-observability-starter (#11579)
34981c9606 is described below
commit 34981c9606facf63000264a71d2a69b93afe2fd1
Author: ShenFeng312 <[email protected]>
AuthorDate: Thu Mar 2 06:37:06 2023 +0800
add dubbo-spring-boot-observability-starter (#11579)
* add dubbo-spring-boot-observability-starter
* add License and fix codestyle
* Add License
* Add dubbo-spring-boot-observability-starter to dubbo-dependencies-all
* Changes following review
* Changes following review
* Polish pom
* Changes following review
* Add dubbo-metrics-default in dubbo-spring-boot-observability-starter
* Remove author tag
* Polish pom
---
.../dubbo-demo-spring-boot-consumer/pom.xml | 9 +-
.../demo/consumer/ObservationConfiguration.java | 215 -----------------
.../dubbo-demo-spring-boot-provider/pom.xml | 8 +-
.../demo/provider/ObservationConfiguration.java | 214 -----------------
dubbo-demo/dubbo-demo-spring-boot/pom.xml | 20 ++
dubbo-dependencies-bom/pom.xml | 1 +
dubbo-distribution/dubbo-bom/pom.xml | 5 +
.../pom.xml | 77 ++++++
.../ConditionalOnDubboTracingEnable.java | 34 +++
.../DubboMicrometerTracingAutoConfiguration.java | 78 ++++++
.../DubboObservationAutoConfiguration.java | 153 ++++++++++++
.../autoconfigure/ObservationHandlerGrouping.java | 74 ++++++
.../ObservationRegistryPostProcessor.java | 54 +++++
.../brave/BraveAutoConfiguration.java | 261 +++++++++++++++++++++
.../otel/OpenTelemetryAutoConfiguration.java | 257 ++++++++++++++++++++
.../config/DubboTracingProperties.java | 191 +++++++++++++++
.../META-INF/spring-configuration-metadata.json | 82 +++++++
.../src/main/resources/META-INF/spring.factories | 6 +
...rk.boot.autoconfigure.AutoConfiguration.imports | 4 +
dubbo-spring-boot/pom.xml | 7 +
dubbo-test/dubbo-dependencies-all/pom.xml | 5 +
21 files changed, 1318 insertions(+), 437 deletions(-)
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 6eec35ee18..626b9d9825 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
@@ -134,15 +134,16 @@
</dependency>
<!-- Observabililty -->
- <dependency>
- <groupId>org.apache.dubbo</groupId>
- <artifactId>dubbo-metrics-default</artifactId>
- </dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-otel</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-spring-boot-observability-starter</artifactId>
+ </dependency>
+
</dependencies>
<build>
diff --git
a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-consumer/src/main/java/org/apache/dubbo/springboot/demo/consumer/ObservationConfiguration.java
b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-consumer/src/main/java/org/apache/dubbo/springboot/demo/consumer/ObservationConfiguration.java
deleted file mode 100644
index 717e36a8f9..0000000000
---
a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-consumer/src/main/java/org/apache/dubbo/springboot/demo/consumer/ObservationConfiguration.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * 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.springboot.demo.consumer;
-
-
-import io.micrometer.core.instrument.MeterRegistry;
-import
io.micrometer.core.instrument.observation.DefaultMeterObservationHandler;
-import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
-import io.micrometer.observation.ObservationHandler;
-import io.micrometer.observation.ObservationRegistry;
-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.TracingAwareMeterObservationHandler;
-import io.micrometer.tracing.otel.bridge.ArrayListSpanProcessor;
-import io.micrometer.tracing.otel.bridge.EventPublishingContextWrapper;
-import io.micrometer.tracing.otel.bridge.OtelBaggageManager;
-import io.micrometer.tracing.otel.bridge.OtelCurrentTraceContext;
-import io.micrometer.tracing.otel.bridge.OtelPropagator;
-import io.micrometer.tracing.otel.bridge.OtelTracer;
-import io.micrometer.tracing.otel.bridge.Slf4JBaggageEventListener;
-import io.micrometer.tracing.otel.bridge.Slf4JEventListener;
-import io.micrometer.tracing.propagation.Propagator;
-import io.opentelemetry.api.common.Attributes;
-import io.opentelemetry.context.ContextStorage;
-import io.opentelemetry.context.propagation.ContextPropagators;
-import io.opentelemetry.extension.trace.propagation.B3Propagator;
-import io.opentelemetry.sdk.OpenTelemetrySdk;
-import io.opentelemetry.sdk.resources.Resource;
-import io.opentelemetry.sdk.trace.SdkTracerProvider;
-import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
-import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
-import org.apache.dubbo.rpc.model.ApplicationModel;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.core.env.Environment;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import java.util.Collections;
-
-import static io.opentelemetry.sdk.trace.samplers.Sampler.alwaysOn;
-
-@Configuration
-public class ObservationConfiguration {
- /**
- * Default value for application name if {@code spring.application.name}
is not set.
- */
- private static final String DEFAULT_APPLICATION_NAME = "application";
-
- @javax.annotation.Resource
- private ApplicationModel applicationModel;
-
- @Bean
- ObservationRegistry observationRegistry() {
- ObservationRegistry observationRegistry = ObservationRegistry.create();
- applicationModel.getBeanFactory().registerBean(observationRegistry);
- return observationRegistry;
-
- }
-
- @Bean
- MeterRegistry meterRegistry() {
- return new SimpleMeterRegistry();
- }
-
- @Bean
- ArrayListSpanProcessor spanExporter() {
- return new ArrayListSpanProcessor();
- }
-
- @Bean
- SdkTracerProvider sdkTracerProvider(Environment environment) {
- String applicationName =
environment.getProperty("dubbo.application.name", DEFAULT_APPLICATION_NAME);
- return SdkTracerProvider.builder().setSampler(alwaysOn())
-
.addSpanProcessor(BatchSpanProcessor.builder(spanExporter()).build())
-
.setResource(Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME,
applicationName)))
- .build();
- }
-
- @Bean
- ContextPropagators contextPropagators() {
- return ContextPropagators.create(B3Propagator.injectingSingleHeader());
- }
-
- @Bean
- OpenTelemetrySdk openTelemetrySdk(SdkTracerProvider sdkTracerProvider) {
- return OpenTelemetrySdk.builder().setTracerProvider(sdkTracerProvider)
- .setPropagators(contextPropagators()).build();
- }
-
- @Bean
- io.opentelemetry.api.trace.Tracer otelTracer(OpenTelemetrySdk
openTelemetrySdk) {
- return openTelemetrySdk.getTracerProvider()
- .get("io.micrometer.micrometer-tracing");
- }
-
- @Bean
- OtelCurrentTraceContext otelCurrentTraceContext() {
- return new OtelCurrentTraceContext();
- }
-
- Slf4JEventListener slf4JEventListener() {
- return new Slf4JEventListener();
- }
-
- Slf4JBaggageEventListener slf4JBaggageEventListener() {
- return new Slf4JBaggageEventListener(Collections.emptyList());
- }
-
- @Bean
- OtelTracer tracer(io.opentelemetry.api.trace.Tracer otelTracer,
OtelCurrentTraceContext otelCurrentTraceContext) {
- Slf4JEventListener slf4JEventListener = slf4JEventListener();
- Slf4JBaggageEventListener slf4JBaggageEventListener =
slf4JBaggageEventListener();
- OtelTracer.EventPublisher eventPublisher = event -> {
- slf4JEventListener.onEvent(event);
- slf4JBaggageEventListener.onEvent(event);
- };
- ContextStorage.addWrapper(new
EventPublishingContextWrapper(eventPublisher));
- return new OtelTracer(otelTracer, otelCurrentTraceContext,
eventPublisher, new OtelBaggageManager(otelCurrentTraceContext,
Collections.emptyList(), Collections.emptyList()));
- }
-
- @Bean
- Propagator propagator(io.opentelemetry.api.trace.Tracer otelTracer) {
- return new OtelPropagator(contextPropagators(), otelTracer);
- }
-
- @Bean
- ObservationHandlerRegistrar
observationHandlerRegistrar(ObservationRegistry observationRegistry, OtelTracer
tracer, Propagator propagator, MeterRegistry meterRegistry) {
- return new ObservationHandlerRegistrar(observationRegistry, tracer,
propagator, meterRegistry);
- }
-
- @Bean
- MetricsDumper metricsDumper(MeterRegistry meterRegistry) {
- return new MetricsDumper(meterRegistry);
- }
-
- @Bean
- TracesDumper tracesDumper(ArrayListSpanProcessor arrayListSpanProcessor) {
- return new TracesDumper(arrayListSpanProcessor);
- }
-
- static class ObservationHandlerRegistrar {
-
- private final ObservationRegistry observationRegistry;
-
- private final Tracer tracer;
-
- private final Propagator propagator;
-
- private final MeterRegistry meterRegistry;
-
- ObservationHandlerRegistrar(ObservationRegistry observationRegistry,
Tracer tracer, Propagator propagator, MeterRegistry meterRegistry) {
- this.observationRegistry = observationRegistry;
- this.tracer = tracer;
- this.propagator = propagator;
- this.meterRegistry = meterRegistry;
- }
-
- @PostConstruct
- void setup() {
- observationRegistry.observationConfig().observationHandler(new
TracingAwareMeterObservationHandler<>(new
DefaultMeterObservationHandler(meterRegistry), tracer));
- observationRegistry.observationConfig()
- .observationHandler(new
ObservationHandler.FirstMatchingCompositeObservationHandler(new
PropagatingReceiverTracingObservationHandler<>(tracer, propagator), new
PropagatingSenderTracingObservationHandler<>(tracer, propagator), new
DefaultTracingObservationHandler(tracer)));
- }
- }
-
-
- static class MetricsDumper {
- private final MeterRegistry meterRegistry;
-
- MetricsDumper(MeterRegistry meterRegistry) {
- this.meterRegistry = meterRegistry;
- }
-
- @PreDestroy
- void dumpMetrics() {
- System.out.println("==== METRICS ====");
- this.meterRegistry.getMeters().forEach(meter ->
System.out.println(" - Metric type \t[" + meter.getId().getType() + "],\tname
[" + meter.getId().getName() + "],\ttags " + meter.getId().getTags() +
",\tmeasurements " + meter.measure()));
- System.out.println("=================");
- }
- }
-
-
- static class TracesDumper {
- private final ArrayListSpanProcessor arrayListSpanProcessor;
-
- TracesDumper(ArrayListSpanProcessor arrayListSpanProcessor) {
- this.arrayListSpanProcessor = arrayListSpanProcessor;
- }
-
- @PreDestroy
- void dumpTraces() {
- System.out.println("==== TRACES ====");
- this.arrayListSpanProcessor.spans().forEach(System.out::println);
- System.out.println("=================");
- }
- }
-}
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 fcb8ec1b11..ba32f8c70e 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
@@ -133,14 +133,14 @@
</dependency>
<!-- Observability -->
- <dependency>
- <groupId>org.apache.dubbo</groupId>
- <artifactId>dubbo-metrics-default</artifactId>
- </dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-otel</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-spring-boot-observability-starter</artifactId>
+ </dependency>
</dependencies>
diff --git
a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-provider/src/main/java/org/apache/dubbo/springboot/demo/provider/ObservationConfiguration.java
b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-provider/src/main/java/org/apache/dubbo/springboot/demo/provider/ObservationConfiguration.java
deleted file mode 100644
index 722427fcc5..0000000000
---
a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-provider/src/main/java/org/apache/dubbo/springboot/demo/provider/ObservationConfiguration.java
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * 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.springboot.demo.provider;
-
-
-import io.micrometer.core.instrument.MeterRegistry;
-import
io.micrometer.core.instrument.observation.DefaultMeterObservationHandler;
-import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
-import io.micrometer.observation.ObservationHandler;
-import io.micrometer.observation.ObservationRegistry;
-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.TracingAwareMeterObservationHandler;
-import io.micrometer.tracing.otel.bridge.ArrayListSpanProcessor;
-import io.micrometer.tracing.otel.bridge.EventPublishingContextWrapper;
-import io.micrometer.tracing.otel.bridge.OtelBaggageManager;
-import io.micrometer.tracing.otel.bridge.OtelCurrentTraceContext;
-import io.micrometer.tracing.otel.bridge.OtelPropagator;
-import io.micrometer.tracing.otel.bridge.OtelTracer;
-import io.micrometer.tracing.otel.bridge.Slf4JBaggageEventListener;
-import io.micrometer.tracing.otel.bridge.Slf4JEventListener;
-import io.micrometer.tracing.propagation.Propagator;
-import io.opentelemetry.api.common.Attributes;
-import io.opentelemetry.context.ContextStorage;
-import io.opentelemetry.context.propagation.ContextPropagators;
-import io.opentelemetry.extension.trace.propagation.B3Propagator;
-import io.opentelemetry.sdk.OpenTelemetrySdk;
-import io.opentelemetry.sdk.resources.Resource;
-import io.opentelemetry.sdk.trace.SdkTracerProvider;
-import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
-import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
-import org.apache.dubbo.rpc.model.ApplicationModel;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.core.env.Environment;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import java.util.Collections;
-
-import static io.opentelemetry.sdk.trace.samplers.Sampler.alwaysOn;
-
-@Configuration
-public class ObservationConfiguration {
-
- /**
- * Default value for application name if {@code spring.application.name}
is not set.
- */
- private static final String DEFAULT_APPLICATION_NAME = "application";
- @javax.annotation.Resource
- private ApplicationModel applicationModel;
-
- @Bean
- ObservationRegistry observationRegistry() {
- ObservationRegistry observationRegistry = ObservationRegistry.create();
- applicationModel.getBeanFactory().registerBean(observationRegistry);
- return observationRegistry;
- }
-
- @Bean
- MeterRegistry meterRegistry() {
- return new SimpleMeterRegistry();
- }
-
- @Bean
- ArrayListSpanProcessor spanExporter() {
- return new ArrayListSpanProcessor();
- }
-
- @Bean
- SdkTracerProvider sdkTracerProvider(Environment environment) {
- String applicationName =
environment.getProperty("dubbo.application.name", DEFAULT_APPLICATION_NAME);
- return SdkTracerProvider.builder().setSampler(alwaysOn())
-
.addSpanProcessor(BatchSpanProcessor.builder(spanExporter()).build())
-
.setResource(Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME,
applicationName)))
- .build();
- }
-
- @Bean
- ContextPropagators contextPropagators() {
- return ContextPropagators.create(B3Propagator.injectingSingleHeader());
- }
-
- @Bean
- OpenTelemetrySdk openTelemetrySdk(SdkTracerProvider sdkTracerProvider) {
- return OpenTelemetrySdk.builder().setTracerProvider(sdkTracerProvider)
- .setPropagators(contextPropagators()).build();
- }
-
- @Bean
- io.opentelemetry.api.trace.Tracer otelTracer(OpenTelemetrySdk
openTelemetrySdk) {
- return openTelemetrySdk.getTracerProvider()
- .get("io.micrometer.micrometer-tracing");
- }
-
- @Bean
- OtelCurrentTraceContext otelCurrentTraceContext() {
- return new OtelCurrentTraceContext();
- }
-
- Slf4JEventListener slf4JEventListener() {
- return new Slf4JEventListener();
- }
-
- Slf4JBaggageEventListener slf4JBaggageEventListener() {
- return new Slf4JBaggageEventListener(Collections.emptyList());
- }
-
- @Bean
- OtelTracer tracer(io.opentelemetry.api.trace.Tracer otelTracer,
OtelCurrentTraceContext otelCurrentTraceContext) {
- Slf4JEventListener slf4JEventListener = slf4JEventListener();
- Slf4JBaggageEventListener slf4JBaggageEventListener =
slf4JBaggageEventListener();
- OtelTracer.EventPublisher eventPublisher = event -> {
- slf4JEventListener.onEvent(event);
- slf4JBaggageEventListener.onEvent(event);
- };
- ContextStorage.addWrapper(new
EventPublishingContextWrapper(eventPublisher));
- return new OtelTracer(otelTracer, otelCurrentTraceContext,
eventPublisher, new OtelBaggageManager(otelCurrentTraceContext,
Collections.emptyList(), Collections.emptyList()));
- }
-
- @Bean
- Propagator propagator(io.opentelemetry.api.trace.Tracer otelTracer) {
- return new OtelPropagator(contextPropagators(), otelTracer);
- }
-
- @Bean
- ObservationHandlerRegistrar
observationHandlerRegistrar(ObservationRegistry observationRegistry, OtelTracer
tracer, Propagator propagator, MeterRegistry meterRegistry) {
- return new ObservationHandlerRegistrar(observationRegistry, tracer,
propagator, meterRegistry);
- }
-
- @Bean
- MetricsDumper metricsDumper(MeterRegistry meterRegistry) {
- return new MetricsDumper(meterRegistry);
- }
-
- @Bean
- TracesDumper tracesDumper(ArrayListSpanProcessor arrayListSpanProcessor) {
- return new TracesDumper(arrayListSpanProcessor);
- }
-
- static class ObservationHandlerRegistrar {
-
- private final ObservationRegistry observationRegistry;
-
- private final Tracer tracer;
-
- private final Propagator propagator;
-
- private final MeterRegistry meterRegistry;
-
- ObservationHandlerRegistrar(ObservationRegistry observationRegistry,
Tracer tracer, Propagator propagator, MeterRegistry meterRegistry) {
- this.observationRegistry = observationRegistry;
- this.tracer = tracer;
- this.propagator = propagator;
- this.meterRegistry = meterRegistry;
- }
-
- @PostConstruct
- void setup() {
- observationRegistry.observationConfig().observationHandler(new
TracingAwareMeterObservationHandler<>(new
DefaultMeterObservationHandler(meterRegistry), tracer));
- observationRegistry.observationConfig()
- .observationHandler(new
ObservationHandler.FirstMatchingCompositeObservationHandler(new
PropagatingReceiverTracingObservationHandler<>(tracer, propagator), new
PropagatingSenderTracingObservationHandler<>(tracer, propagator), new
DefaultTracingObservationHandler(tracer)));
- }
- }
-
-
- static class MetricsDumper {
- private final MeterRegistry meterRegistry;
-
- MetricsDumper(MeterRegistry meterRegistry) {
- this.meterRegistry = meterRegistry;
- }
-
- @PreDestroy
- void dumpMetrics() {
- System.out.println("==== METRICS ====");
- this.meterRegistry.getMeters().forEach(meter ->
System.out.println(" - Metric type \t[" + meter.getId().getType() + "],\tname
[" + meter.getId().getName() + "],\ttags " + meter.getId().getTags() +
",\tmeasurements " + meter.measure()));
- System.out.println("=================");
- }
- }
-
-
- static class TracesDumper {
- private final ArrayListSpanProcessor arrayListSpanProcessor;
-
- TracesDumper(ArrayListSpanProcessor arrayListSpanProcessor) {
- this.arrayListSpanProcessor = arrayListSpanProcessor;
- }
-
- @PreDestroy
- void dumpTraces() {
- System.out.println("==== TRACES ====");
- this.arrayListSpanProcessor.spans().forEach(System.out::println);
- System.out.println("=================");
- }
- }
-}
diff --git a/dubbo-demo/dubbo-demo-spring-boot/pom.xml
b/dubbo-demo/dubbo-demo-spring-boot/pom.xml
index 4cd2703b11..18546bdbec 100644
--- a/dubbo-demo/dubbo-demo-spring-boot/pom.xml
+++ b/dubbo-demo/dubbo-demo-spring-boot/pom.xml
@@ -36,7 +36,27 @@
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<skip_maven_deploy>true</skip_maven_deploy>
+ <spring-boot.version>2.7.8</spring-boot.version>
<spring-boot-maven-plugin.version>2.7.8</spring-boot-maven-plugin.version>
+ <micrometer-core.version>1.10.4</micrometer-core.version>
</properties>
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-dependencies</artifactId>
+ <version>${spring-boot.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ <dependency>
+ <groupId>io.micrometer</groupId>
+ <artifactId>micrometer-core</artifactId>
+ <version>${micrometer-core.version}</version>
+ </dependency>
+ </dependencies>
+
+ </dependencyManagement>
+
</project>
diff --git a/dubbo-dependencies-bom/pom.xml b/dubbo-dependencies-bom/pom.xml
index 7208334a6e..e5d57f3907 100644
--- a/dubbo-dependencies-bom/pom.xml
+++ b/dubbo-dependencies-bom/pom.xml
@@ -135,6 +135,7 @@
<protostuff_version>1.8.0</protostuff_version>
<envoy_api_version>0.1.35</envoy_api_version>
<micrometer.version>1.10.4</micrometer.version>
+
<micrometer-tracing.version>1.0.2</micrometer-tracing.version>
<t_digest.version>3.3</t_digest.version>
<prometheus_client.version>0.16.0</prometheus_client.version>
diff --git a/dubbo-distribution/dubbo-bom/pom.xml
b/dubbo-distribution/dubbo-bom/pom.xml
index 988e6cc411..9e04c68747 100644
--- a/dubbo-distribution/dubbo-bom/pom.xml
+++ b/dubbo-distribution/dubbo-bom/pom.xml
@@ -487,6 +487,11 @@
<type>pom</type>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+
<artifactId>dubbo-spring-boot-observability-starter</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<!-- test -->
<dependency>
diff --git a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/pom.xml
b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/pom.xml
new file mode 100644
index 0000000000..5922c1450c
--- /dev/null
+++ b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/pom.xml
@@ -0,0 +1,77 @@
+<?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>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-spring-boot</artifactId>
+ <version>${revision}</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>dubbo-spring-boot-observability-starter</artifactId>
+
+ <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>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.apache.dubbo</groupId>
+ <artifactId>dubbo-common</artifactId>
+ <version>${project.version}</version>
+ <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-metrics-default</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+</project>
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/src/main/java/org/apache/dubbo/spring/boot/observability/annotation/ConditionalOnDubboTracingEnable.java
new file mode 100644
index 0000000000..5e6d05f9ce
--- /dev/null
+++
b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/annotation/ConditionalOnDubboTracingEnable.java
@@ -0,0 +1,34 @@
+/*
+ * 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.annotation;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.TYPE,ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+@Documented
+@ConditionalOnProperty(prefix = "dubbo.tracing", 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/DubboMicrometerTracingAutoConfiguration.java
b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/DubboMicrometerTracingAutoConfiguration.java
new file mode 100644
index 0000000000..a1f44a1867
--- /dev/null
+++
b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/DubboMicrometerTracingAutoConfiguration.java
@@ -0,0 +1,78 @@
+/*
+ * 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;
+
+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.propagation.Propagator;
+import
org.apache.dubbo.spring.boot.observability.annotation.ConditionalOnDubboTracingEnable;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.core.annotation.Order;
+
+/**
+ * copy from {@link
org.springframework.boot.actuate.autoconfigure.tracing.MicrometerTracingAutoConfiguration}
+ * this class is available starting from Boot 3.0. It's not available if
you're using Boot < 3.0
+ */
+@ConditionalOnClass(Tracer.class)
+@ConditionalOnDubboTracingEnable
+@AutoConfigureAfter(name =
"org.springframework.boot.actuate.autoconfigure.tracing.MicrometerTracingAutoConfiguration")
+public class DubboMicrometerTracingAutoConfiguration {
+
+ /**
+ * {@code @Order} value of
+ * {@link #propagatingReceiverTracingObservationHandler(Tracer,
Propagator)}.
+ */
+ public static final int RECEIVER_TRACING_OBSERVATION_HANDLER_ORDER = 1000;
+
+ /**
+ * {@code @Order} value of
+ * {@link #propagatingSenderTracingObservationHandler(Tracer, Propagator)}.
+ */
+ public static final int SENDER_TRACING_OBSERVATION_HANDLER_ORDER = 2000;
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnBean(Tracer.class)
+ public DefaultTracingObservationHandler
defaultTracingObservationHandler(Tracer tracer) {
+ return new DefaultTracingObservationHandler(tracer);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnBean({Tracer.class, Propagator.class})
+ @Order(SENDER_TRACING_OBSERVATION_HANDLER_ORDER)
+ public PropagatingSenderTracingObservationHandler<?>
propagatingSenderTracingObservationHandler(Tracer tracer,
+
Propagator propagator) {
+ return new PropagatingSenderTracingObservationHandler<>(tracer,
propagator);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnBean({Tracer.class, Propagator.class})
+ @Order(RECEIVER_TRACING_OBSERVATION_HANDLER_ORDER)
+ public PropagatingReceiverTracingObservationHandler<?>
propagatingReceiverTracingObservationHandler(Tracer tracer,
+
Propagator propagator) {
+ return new PropagatingReceiverTracingObservationHandler<>(tracer,
propagator);
+ }
+
+}
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/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/DubboObservationAutoConfiguration.java
new file mode 100644
index 0000000000..d50881e3c4
--- /dev/null
+++
b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/DubboObservationAutoConfiguration.java
@@ -0,0 +1,153 @@
+/*
+ * 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;
+
+import io.micrometer.core.instrument.MeterRegistry;
+import
io.micrometer.core.instrument.observation.DefaultMeterObservationHandler;
+import io.micrometer.core.instrument.observation.MeterObservationHandler;
+import io.micrometer.observation.Observation;
+import io.micrometer.observation.ObservationHandler;
+import io.micrometer.observation.ObservationRegistry;
+import io.micrometer.tracing.Tracer;
+import io.micrometer.tracing.handler.TracingAwareMeterObservationHandler;
+import io.micrometer.tracing.handler.TracingObservationHandler;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+import
org.apache.dubbo.spring.boot.observability.annotation.ConditionalOnDubboTracingEnable;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
+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;
+import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.Arrays;
+
+/**
+ * Register observationRegistry to ApplicationModel.
+ * Create observationRegistry when you are using Boot <3.0 or you are not
using spring-boot-starter-actuator
+ */
+@AutoConfiguration(after
=DubboMicrometerTracingAutoConfiguration.class,afterName =
"org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration")
+@ConditionalOnDubboTracingEnable
+public class DubboObservationAutoConfiguration implements BeanFactoryAware,
SmartInitializingSingleton {
+
+ public DubboObservationAutoConfiguration(ApplicationModel
applicationModel) {
+ this.applicationModel = applicationModel;
+ }
+
+ private final ApplicationModel applicationModel;
+
+ private BeanFactory beanFactory;
+
+ @Bean
+ @ConditionalOnMissingBean
+ ObservationRegistry observationRegistry() {
+ return ObservationRegistry.create();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean(type =
"org.springframework.boot.actuate.autoconfigure.observation.ObservationRegistryPostProcessor")
+ public ObservationRegistryPostProcessor
dubboObservationRegistryPostProcessor(ObjectProvider<ObservationHandlerGrouping>
observationHandlerGrouping,
+
ObjectProvider<ObservationHandler<?>> observationHandlers) {
+ return new
ObservationRegistryPostProcessor(observationHandlerGrouping,
observationHandlers);
+ }
+
+ @Override
+ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
+ this.beanFactory = beanFactory;
+ }
+
+ @Override
+ public void afterSingletonsInstantiated() {
+
applicationModel.getBeanFactory().registerBean(beanFactory.getBean(ObservationRegistry.class));
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ @ConditionalOnClass(MeterRegistry.class)
+ @ConditionalOnMissingClass("io.micrometer.tracing.Tracer")
+ @ConditionalOnMissingBean(type =
"org.springframework.boot.actuate.autoconfigure.observation.ObservationRegistryPostProcessor")
+ static class OnlyMetricsConfiguration {
+
+ @Bean
+ ObservationHandlerGrouping metricsObservationHandlerGrouping() {
+ return new
ObservationHandlerGrouping(MeterObservationHandler.class);
+ }
+
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ @ConditionalOnClass(Tracer.class)
+ @ConditionalOnMissingClass("io.micrometer.core.instrument.MeterRegistry")
+ @ConditionalOnMissingBean(type =
"org.springframework.boot.actuate.autoconfigure.observation.ObservationRegistryPostProcessor")
+ static class OnlyTracingConfiguration {
+
+ @Bean
+ ObservationHandlerGrouping tracingObservationHandlerGrouping() {
+ return new
ObservationHandlerGrouping(TracingObservationHandler.class);
+ }
+
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ @ConditionalOnClass({ MeterRegistry.class, Tracer.class })
+ @ConditionalOnMissingBean(type =
"org.springframework.boot.actuate.autoconfigure.observation.ObservationRegistryPostProcessor")
+ static class MetricsWithTracingConfiguration {
+
+ @Bean
+ ObservationHandlerGrouping
metricsAndTracingObservationHandlerGrouping() {
+ return new ObservationHandlerGrouping(
+ Arrays.asList(TracingObservationHandler.class,
MeterObservationHandler.class));
+ }
+
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ @ConditionalOnBean(MeterRegistry.class)
+ @ConditionalOnMissingBean(MeterObservationHandler.class)
+ static class MeterObservationHandlerConfiguration {
+
+ @ConditionalOnMissingBean(type = "io.micrometer.tracing.Tracer")
+ @Configuration(proxyBeanMethods = false)
+ static class OnlyMetricsMeterObservationHandlerConfiguration {
+
+ @Bean
+ DefaultMeterObservationHandler
defaultMeterObservationHandler(MeterRegistry meterRegistry) {
+ return new DefaultMeterObservationHandler(meterRegistry);
+ }
+
+ }
+
+ @ConditionalOnBean(Tracer.class)
+ @Configuration(proxyBeanMethods = false)
+ static class TracingAndMetricsObservationHandlerConfiguration {
+
+ @Bean
+ TracingAwareMeterObservationHandler<Observation.Context>
tracingAwareMeterObservationHandler(
+ MeterRegistry meterRegistry, Tracer tracer) {
+ DefaultMeterObservationHandler delegate = new
DefaultMeterObservationHandler(meterRegistry);
+ return new TracingAwareMeterObservationHandler<>(delegate,
tracer);
+ }
+
+ }
+
+ }
+}
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/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservationHandlerGrouping.java
new file mode 100644
index 0000000000..1c3df96886
--- /dev/null
+++
b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservationHandlerGrouping.java
@@ -0,0 +1,74 @@
+/*
+ * 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;
+
+import io.micrometer.observation.ObservationHandler;
+import io.micrometer.observation.ObservationRegistry;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Groups {@link ObservationHandler ObservationHandlers} by type.
+ * copy from {@link
org.springframework.boot.actuate.autoconfigure.observation.ObservationHandlerGrouping}
+ * this class is available starting from Boot 3.0. It's not available if
you're using Boot < 3.0
+ *
+ * @author Andy Wilkinson
+ */
+class ObservationHandlerGrouping {
+
+ private final List<Class<? extends ObservationHandler>> categories;
+
+ ObservationHandlerGrouping(Class<? extends ObservationHandler> category) {
+ this(Collections.singletonList(category));
+ }
+
+ ObservationHandlerGrouping(List<Class<? extends ObservationHandler>>
categories) {
+ this.categories = categories;
+ }
+
+ void apply(List<ObservationHandler<?>> handlers,
ObservationRegistry.ObservationConfig config) {
+ MultiValueMap<Class<? extends ObservationHandler>,
ObservationHandler<?>> groupings = new LinkedMultiValueMap<>();
+ for (ObservationHandler<?> handler : handlers) {
+ Class<? extends ObservationHandler> category =
findCategory(handler);
+ if (category != null) {
+ groupings.add(category, handler);
+ } else {
+ config.observationHandler(handler);
+ }
+ }
+ for (Class<? extends ObservationHandler> category : this.categories) {
+ List<ObservationHandler<?>> handlerGroup = groupings.get(category);
+ if (!CollectionUtils.isEmpty(handlerGroup)) {
+ config.observationHandler(new
ObservationHandler.FirstMatchingCompositeObservationHandler(handlerGroup));
+ }
+ }
+ }
+
+ private Class<? extends ObservationHandler>
findCategory(ObservationHandler<?> handler) {
+ for (Class<? extends ObservationHandler> category : this.categories) {
+ if (category.isInstance(handler)) {
+ return category;
+ }
+ }
+ return null;
+ }
+
+}
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/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservationRegistryPostProcessor.java
new file mode 100644
index 0000000000..47344b3f40
--- /dev/null
+++
b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservationRegistryPostProcessor.java
@@ -0,0 +1,54 @@
+/*
+ * 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;
+
+import io.micrometer.observation.ObservationHandler;
+import io.micrometer.observation.ObservationRegistry;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * registry observationHandlers to observationConfig
+ */
+public class ObservationRegistryPostProcessor implements BeanPostProcessor {
+ private final ObjectProvider<ObservationHandlerGrouping>
observationHandlerGrouping;
+ private final ObjectProvider<ObservationHandler<?>> observationHandlers;
+
+ public
ObservationRegistryPostProcessor(ObjectProvider<ObservationHandlerGrouping>
observationHandlerGrouping,
+
ObjectProvider<ObservationHandler<?>> observationHandlers){
+ this.observationHandlerGrouping = observationHandlerGrouping;
+ this.observationHandlers = observationHandlers;
+
+ }
+ @Override
+ public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
+ if(bean instanceof ObservationRegistry){
+ ObservationRegistry observationRegistry = (ObservationRegistry)
bean;
+ List<ObservationHandler<?>> observationHandlerList =
+
observationHandlers.orderedStream().collect(Collectors.toList());
+ observationHandlerGrouping.ifAvailable(grouping->{
+ grouping.apply(observationHandlerList,
+ observationRegistry.observationConfig());
+ });
+ }
+ return bean;
+ }
+}
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/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/brave/BraveAutoConfiguration.java
new file mode 100644
index 0000000000..dd6c1cc6cc
--- /dev/null
+++
b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/brave/BraveAutoConfiguration.java
@@ -0,0 +1,261 @@
+/*
+ * 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.brave;
+
+import brave.CurrentSpanCustomizer;
+import brave.SpanCustomizer;
+import brave.Tracing;
+import brave.TracingCustomizer;
+import brave.baggage.BaggageField;
+import brave.baggage.BaggagePropagation;
+import brave.baggage.BaggagePropagationConfig;
+import brave.baggage.BaggagePropagationCustomizer;
+import brave.baggage.CorrelationScopeConfig;
+import brave.baggage.CorrelationScopeCustomizer;
+import brave.baggage.CorrelationScopeDecorator;
+import brave.context.slf4j.MDCScopeDecorator;
+import brave.handler.SpanHandler;
+import brave.propagation.B3Propagation;
+import brave.propagation.CurrentTraceContext;
+import brave.propagation.CurrentTraceContextCustomizer;
+import brave.propagation.Propagation;
+import brave.propagation.ThreadLocalCurrentTraceContext;
+import brave.sampler.Sampler;
+import io.micrometer.tracing.Tracer;
+import io.micrometer.tracing.brave.bridge.BraveBaggageManager;
+import io.micrometer.tracing.brave.bridge.BraveCurrentTraceContext;
+import io.micrometer.tracing.brave.bridge.BravePropagator;
+import io.micrometer.tracing.brave.bridge.BraveSpanCustomizer;
+import io.micrometer.tracing.brave.bridge.BraveTracer;
+import io.micrometer.tracing.brave.bridge.CompositeSpanHandler;
+import io.micrometer.tracing.brave.bridge.W3CPropagation;
+import io.micrometer.tracing.exporter.SpanExportingPredicate;
+import io.micrometer.tracing.exporter.SpanFilter;
+import io.micrometer.tracing.exporter.SpanReporter;
+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.config.DubboTracingProperties;
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import
org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+import org.springframework.core.env.Environment;
+
+import java.util.Collections;
+import java.util.List;
+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({Tracer.class, BraveTracer.class})
+@EnableConfigurationProperties(DubboTracingProperties.class)
+@ConditionalOnDubboTracingEnable
+public class BraveAutoConfiguration {
+
+ private static final BraveBaggageManager BRAVE_BAGGAGE_MANAGER = new
BraveBaggageManager();
+
+ /**
+ * Default value for application name if {@code spring.application.name}
is not set.
+ */
+ private static final String DEFAULT_APPLICATION_NAME = "application";
+
+ @Bean
+ @ConditionalOnMissingBean
+ @Order(Ordered.HIGHEST_PRECEDENCE)
+ CompositeSpanHandler
compositeSpanHandler(ObjectProvider<SpanExportingPredicate> predicates,
+ ObjectProvider<SpanReporter>
reporters, ObjectProvider<SpanFilter> filters) {
+ return new
CompositeSpanHandler(predicates.orderedStream().collect(Collectors.toList()),
+ reporters.orderedStream().collect(Collectors.toList()),
+ filters.orderedStream().collect(Collectors.toList()));
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public Tracing braveTracing(Environment environment, List<SpanHandler>
spanHandlers,
+ List<TracingCustomizer> tracingCustomizers,
CurrentTraceContext currentTraceContext,
+ Propagation.Factory propagationFactory,
Sampler sampler) {
+ String applicationName =
environment.getProperty("spring.application.name", DEFAULT_APPLICATION_NAME);
+ Tracing.Builder builder =
Tracing.newBuilder().currentTraceContext(currentTraceContext).traceId128Bit(true)
+
.supportsJoin(false).propagationFactory(propagationFactory).sampler(sampler)
+ .localServiceName(applicationName);
+ spanHandlers.forEach(builder::addSpanHandler);
+ for (TracingCustomizer tracingCustomizer : tracingCustomizers) {
+ tracingCustomizer.customize(builder);
+ }
+ return builder.build();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public brave.Tracer braveTracer(Tracing tracing) {
+ return tracing.tracer();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public CurrentTraceContext
braveCurrentTraceContext(List<CurrentTraceContext.ScopeDecorator>
scopeDecorators,
+
List<CurrentTraceContextCustomizer> currentTraceContextCustomizers) {
+ ThreadLocalCurrentTraceContext.Builder builder =
ThreadLocalCurrentTraceContext.newBuilder();
+ scopeDecorators.forEach(builder::addScopeDecorator);
+ for (CurrentTraceContextCustomizer currentTraceContextCustomizer :
currentTraceContextCustomizers) {
+ currentTraceContextCustomizer.customize(builder);
+ }
+ return builder.build();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public Sampler braveSampler(DubboTracingProperties properties) {
+ return Sampler.create(properties.getSampling().getProbability());
+ }
+
+ @Bean
+ @ConditionalOnMissingBean(io.micrometer.tracing.Tracer.class)
+ BraveTracer braveTracerBridge(brave.Tracer tracer, CurrentTraceContext
currentTraceContext) {
+ return new BraveTracer(tracer, new
BraveCurrentTraceContext(currentTraceContext), BRAVE_BAGGAGE_MANAGER);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ BravePropagator bravePropagator(Tracing tracing) {
+ return new BravePropagator(tracing);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean(SpanCustomizer.class)
+ CurrentSpanCustomizer currentSpanCustomizer(Tracing tracing) {
+ return CurrentSpanCustomizer.create(tracing);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean(io.micrometer.tracing.SpanCustomizer.class)
+ BraveSpanCustomizer braveSpanCustomizer(SpanCustomizer spanCustomizer) {
+ return new BraveSpanCustomizer(spanCustomizer);
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ @ConditionalOnProperty(value = "dubbo.tracing.baggage.enabled",
havingValue = "false")
+ static class BraveNoBaggageConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean
+ Propagation.Factory propagationFactory(DubboTracingProperties tracing)
{
+ DubboTracingProperties.Propagation.PropagationType type =
tracing.getPropagation().getType();
+ switch (type) {
+ case B3:
+ return
B3Propagation.newFactoryBuilder().injectFormat(B3Propagation.Format.SINGLE_NO_PARENT).build();
+ case W3C:
+ return new W3CPropagation();
+ default:
+ throw new IllegalArgumentException("UnSupport propagation
type");
+ }
+ }
+
+ }
+
+ @ConditionalOnProperty(value = "dubbo.tracing.baggage.enabled",
matchIfMissing = true)
+ @Configuration(proxyBeanMethods = false)
+ static class BraveBaggageConfiguration {
+ private final DubboTracingProperties dubboTracingProperties;
+
+ public BraveBaggageConfiguration(DubboTracingProperties
dubboTracingProperties) {
+ this.dubboTracingProperties = dubboTracingProperties;
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnProperty(prefix = "dubbo.tracing.propagation", value =
"type", havingValue = "B3")
+ BaggagePropagation.FactoryBuilder b3PropagationFactoryBuilder(
+ ObjectProvider<BaggagePropagationCustomizer>
baggagePropagationCustomizers) {
+ Propagation.Factory delegate =
+
B3Propagation.newFactoryBuilder().injectFormat(B3Propagation.Format.SINGLE_NO_PARENT).build();
+
+ BaggagePropagation.FactoryBuilder builder =
BaggagePropagation.newFactoryBuilder(delegate);
+ baggagePropagationCustomizers.orderedStream().forEach((customizer)
-> customizer.customize(builder));
+ return builder;
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnProperty(prefix = "dubbo.tracing.propagation", value =
"type", havingValue = "W3C", matchIfMissing = true)
+ BaggagePropagation.FactoryBuilder w3cPropagationFactoryBuilder(
+ ObjectProvider<BaggagePropagationCustomizer>
baggagePropagationCustomizers) {
+ Propagation.Factory delegate = new
W3CPropagation(BRAVE_BAGGAGE_MANAGER, Collections.emptyList());
+
+ BaggagePropagation.FactoryBuilder builder =
BaggagePropagation.newFactoryBuilder(delegate);
+ baggagePropagationCustomizers.orderedStream().forEach((customizer)
-> customizer.customize(builder));
+ return builder;
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ @Order(0)
+ BaggagePropagationCustomizer
remoteFieldsBaggagePropagationCustomizer() {
+ return (builder) -> {
+ List<String> remoteFields =
dubboTracingProperties.getBaggage().getRemoteFields();
+ for (String fieldName : remoteFields) {
+
builder.add(BaggagePropagationConfig.SingleBaggageField.remote(BaggageField.create(fieldName)));
+ }
+ };
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ Propagation.Factory
propagationFactory(BaggagePropagation.FactoryBuilder factoryBuilder) {
+ return factoryBuilder.build();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ CorrelationScopeDecorator.Builder mdcCorrelationScopeDecoratorBuilder(
+ ObjectProvider<CorrelationScopeCustomizer>
correlationScopeCustomizers) {
+ CorrelationScopeDecorator.Builder builder =
MDCScopeDecorator.newBuilder();
+ correlationScopeCustomizers.orderedStream().forEach((customizer)
-> customizer.customize(builder));
+ return builder;
+ }
+
+ @Bean
+ @Order(0)
+ @ConditionalOnProperty(prefix = "dubbo.tracing.baggage.correlation",
name = "enabled",
+ matchIfMissing = true)
+ CorrelationScopeCustomizer
correlationFieldsCorrelationScopeCustomizer() {
+ return (builder) -> {
+ List<String> correlationFields =
this.dubboTracingProperties.getBaggage().getCorrelation().getFields();
+ for (String field : correlationFields) {
+
builder.add(CorrelationScopeConfig.SingleCorrelationField.newBuilder(BaggageField.create(field))
+ .flushOnUpdate().build());
+ }
+ };
+ }
+
+ @Bean
+ @ConditionalOnMissingBean(CurrentTraceContext.ScopeDecorator.class)
+ CurrentTraceContext.ScopeDecorator
correlationScopeDecorator(CorrelationScopeDecorator.Builder builder) {
+ return builder.build();
+ }
+
+ }
+
+}
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/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/otel/OpenTelemetryAutoConfiguration.java
new file mode 100644
index 0000000000..c2903fa46d
--- /dev/null
+++
b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/otel/OpenTelemetryAutoConfiguration.java
@@ -0,0 +1,257 @@
+/*
+ * 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.otel;
+
+import io.micrometer.tracing.SpanCustomizer;
+import io.micrometer.tracing.exporter.SpanExportingPredicate;
+import io.micrometer.tracing.exporter.SpanFilter;
+import io.micrometer.tracing.exporter.SpanReporter;
+import io.micrometer.tracing.otel.bridge.CompositeSpanExporter;
+import io.micrometer.tracing.otel.bridge.EventListener;
+import io.micrometer.tracing.otel.bridge.EventPublishingContextWrapper;
+import io.micrometer.tracing.otel.bridge.OtelBaggageManager;
+import io.micrometer.tracing.otel.bridge.OtelCurrentTraceContext;
+import io.micrometer.tracing.otel.bridge.OtelPropagator;
+import io.micrometer.tracing.otel.bridge.OtelSpanCustomizer;
+import io.micrometer.tracing.otel.bridge.OtelTracer;
+import io.micrometer.tracing.otel.bridge.Slf4JBaggageEventListener;
+import io.micrometer.tracing.otel.bridge.Slf4JEventListener;
+import io.micrometer.tracing.otel.propagation.BaggageTextMapPropagator;
+import io.opentelemetry.api.OpenTelemetry;
+import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator;
+import io.opentelemetry.api.common.Attributes;
+import io.opentelemetry.api.trace.Tracer;
+import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator;
+import io.opentelemetry.context.ContextStorage;
+import io.opentelemetry.context.propagation.ContextPropagators;
+import io.opentelemetry.context.propagation.TextMapPropagator;
+import io.opentelemetry.extension.trace.propagation.B3Propagator;
+import io.opentelemetry.sdk.OpenTelemetrySdk;
+import io.opentelemetry.sdk.resources.Resource;
+import io.opentelemetry.sdk.trace.SdkTracerProvider;
+import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder;
+import io.opentelemetry.sdk.trace.SpanProcessor;
+import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
+import io.opentelemetry.sdk.trace.export.SpanExporter;
+import io.opentelemetry.sdk.trace.samplers.Sampler;
+import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
+import org.apache.dubbo.common.Version;
+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.config.DubboTracingProperties;
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import
org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * provider OpenTelemetry 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.OpenTelemetryAutoConfiguration")
+@ConditionalOnDubboTracingEnable
+@ConditionalOnClass({OtelTracer.class, SdkTracerProvider.class,
OpenTelemetry.class})
+@EnableConfigurationProperties(DubboTracingProperties.class)
+public class OpenTelemetryAutoConfiguration {
+
+ /**
+ * Default value for application name if {@code spring.application.name}
is not set.
+ */
+ private static final String DEFAULT_APPLICATION_NAME = "application";
+
+ private final DubboTracingProperties dubboTracingProperties;
+
+ OpenTelemetryAutoConfiguration(DubboTracingProperties
dubboTracingProperties) {
+ this.dubboTracingProperties = dubboTracingProperties;
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ OpenTelemetry openTelemetry(SdkTracerProvider sdkTracerProvider,
ContextPropagators contextPropagators) {
+ return
OpenTelemetrySdk.builder().setTracerProvider(sdkTracerProvider).setPropagators(contextPropagators)
+ .build();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ SdkTracerProvider otelSdkTracerProvider(Environment environment,
ObjectProvider<SpanProcessor> spanProcessors,
+ Sampler sampler) {
+ String applicationName =
environment.getProperty("spring.application.name", DEFAULT_APPLICATION_NAME);
+ SdkTracerProviderBuilder builder =
SdkTracerProvider.builder().setSampler(sampler)
+
.setResource(Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME,
applicationName)));
+ spanProcessors.orderedStream().forEach(builder::addSpanProcessor);
+ return builder.build();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ ContextPropagators
otelContextPropagators(ObjectProvider<TextMapPropagator> textMapPropagators) {
+ return
ContextPropagators.create(TextMapPropagator.composite(textMapPropagators.orderedStream().collect(Collectors.toList())));
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ Sampler otelSampler() {
+ Sampler rootSampler =
Sampler.traceIdRatioBased(this.dubboTracingProperties.getSampling().getProbability());
+ return Sampler.parentBased(rootSampler);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ SpanProcessor otelSpanProcessor(ObjectProvider<SpanExporter> spanExporters,
+ ObjectProvider<SpanExportingPredicate>
spanExportingPredicates, ObjectProvider<SpanReporter> spanReporters,
+ ObjectProvider<SpanFilter> spanFilters) {
+ return BatchSpanProcessor.builder(new
CompositeSpanExporter(spanExporters.orderedStream().collect(Collectors.toList()),
+
spanExportingPredicates.orderedStream().collect(Collectors.toList()),
spanReporters.orderedStream().collect(Collectors.toList()),
+ spanFilters.orderedStream().collect(Collectors.toList()))).build();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ Tracer otelTracer(OpenTelemetry openTelemetry) {
+ return openTelemetry.getTracer("org.apache.dubbo",
Version.getVersion());
+ }
+
+ @Bean
+ @ConditionalOnMissingBean(io.micrometer.tracing.Tracer.class)
+ OtelTracer micrometerOtelTracer(Tracer tracer, OtelTracer.EventPublisher
eventPublisher,
+ OtelCurrentTraceContext
otelCurrentTraceContext) {
+ return new OtelTracer(tracer, otelCurrentTraceContext, eventPublisher,
+ new OtelBaggageManager(otelCurrentTraceContext,
this.dubboTracingProperties.getBaggage().getRemoteFields(),
+ Collections.emptyList()));
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ OtelPropagator otelPropagator(ContextPropagators contextPropagators,
Tracer tracer) {
+ return new OtelPropagator(contextPropagators, tracer);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ OtelTracer.EventPublisher otelTracerEventPublisher(List<EventListener>
eventListeners) {
+ return new OTelEventPublisher(eventListeners);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ OtelCurrentTraceContext otelCurrentTraceContext(OtelTracer.EventPublisher
publisher) {
+ ContextStorage.addWrapper(new
EventPublishingContextWrapper(publisher));
+ return new OtelCurrentTraceContext();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ Slf4JEventListener otelSlf4JEventListener() {
+ return new Slf4JEventListener();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean(SpanCustomizer.class)
+ OtelSpanCustomizer otelSpanCustomizer() {
+ return new OtelSpanCustomizer();
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ @ConditionalOnProperty(prefix = "dubbo.tracing.baggage", name = "enabled",
matchIfMissing = true)
+ static class BaggageConfiguration {
+
+ private final DubboTracingProperties tracingProperties;
+
+ BaggageConfiguration(DubboTracingProperties tracingProperties) {
+ this.tracingProperties = tracingProperties;
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnProperty(prefix = "dubbo.tracing.propagation", name =
"type", havingValue = "W3C",
+ matchIfMissing = true)
+ TextMapPropagator
w3cTextMapPropagatorWithBaggage(OtelCurrentTraceContext
otelCurrentTraceContext) {
+ List<String> remoteFields =
this.tracingProperties.getBaggage().getRemoteFields();
+ return
TextMapPropagator.composite(W3CTraceContextPropagator.getInstance(),
+ W3CBaggagePropagator.getInstance(), new
BaggageTextMapPropagator(remoteFields,
+ new OtelBaggageManager(otelCurrentTraceContext,
remoteFields, Collections.emptyList())));
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnProperty(prefix = "dubbo.tracing.propagation", name =
"type", havingValue = "B3")
+ TextMapPropagator b3BaggageTextMapPropagator(OtelCurrentTraceContext
otelCurrentTraceContext) {
+ List<String> remoteFields =
this.tracingProperties.getBaggage().getRemoteFields();
+ return
TextMapPropagator.composite(B3Propagator.injectingSingleHeader(),
+ new BaggageTextMapPropagator(remoteFields,
+ new OtelBaggageManager(otelCurrentTraceContext,
remoteFields, Collections.emptyList())));
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnProperty(prefix = "dubbo.tracing.baggage.correlation",
name = "enabled",
+ matchIfMissing = true)
+ Slf4JBaggageEventListener otelSlf4JBaggageEventListener() {
+ return new
Slf4JBaggageEventListener(this.tracingProperties.getBaggage().getCorrelation().getFields());
+ }
+
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ @ConditionalOnProperty(prefix = "dubbo.tracing.baggage", name = "enabled",
havingValue = "false")
+ static class NoBaggageConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnProperty(prefix = "dubbo.tracing.propagation", name =
"type", havingValue = "B3")
+ B3Propagator b3TextMapPropagator() {
+ return B3Propagator.injectingSingleHeader();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnProperty(prefix = "dubbo.tracing.propagation", name =
"type", havingValue = "W3C",
+ matchIfMissing = true)
+ W3CTraceContextPropagator w3cTextMapPropagatorWithoutBaggage() {
+ return W3CTraceContextPropagator.getInstance();
+ }
+
+ }
+
+ static class OTelEventPublisher implements OtelTracer.EventPublisher {
+
+ private final List<EventListener> listeners;
+
+ OTelEventPublisher(List<EventListener> listeners) {
+ this.listeners = listeners;
+ }
+
+ @Override
+ public void publishEvent(Object event) {
+ for (EventListener listener : this.listeners) {
+ listener.onEvent(event);
+ }
+ }
+
+ }
+
+}
+
diff --git
a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/config/DubboTracingProperties.java
b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/config/DubboTracingProperties.java
new file mode 100644
index 0000000000..72d4b967df
--- /dev/null
+++
b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/config/DubboTracingProperties.java
@@ -0,0 +1,191 @@
+/*
+ * 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.config;
+
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@ConfigurationProperties("dubbo.tracing")
+public class DubboTracingProperties {
+
+ /**
+ * Whether auto-configuration of tracing is enabled.
+ */
+ private boolean enabled = true;
+
+ /**
+ * Sampling configuration.
+ */
+ private final Sampling sampling = new Sampling();
+
+ /**
+ * Baggage configuration.
+ */
+ private final Baggage baggage = new Baggage();
+
+ /**
+ * Propagation configuration.
+ */
+ private final Propagation propagation = new Propagation();
+
+ public boolean isEnabled() {
+ return this.enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public Sampling getSampling() {
+ return this.sampling;
+ }
+
+ public Baggage getBaggage() {
+ return this.baggage;
+ }
+
+ public Propagation getPropagation() {
+ return this.propagation;
+ }
+
+ public static class Sampling {
+
+ /**
+ * Probability in the range from 0.0 to 1.0 that a trace will be
sampled.
+ */
+ private float probability = 0.10f;
+
+ public float getProbability() {
+ return this.probability;
+ }
+
+ public void setProbability(float probability) {
+ this.probability = probability;
+ }
+
+ }
+
+ public static class Baggage {
+
+ /**
+ * Whether to enable Micrometer Tracing baggage propagation.
+ */
+ private boolean enabled = true;
+
+ /**
+ * Correlation configuration.
+ */
+ private Correlation correlation = new Correlation();
+
+ /**
+ * List of fields that are referenced the same in-process as it is on
the wire.
+ * For example, the field "x-vcap-request-id" would be set as-is
including the
+ * prefix.
+ */
+ private List<String> remoteFields = new ArrayList<>();
+
+ public boolean isEnabled() {
+ return this.enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public Correlation getCorrelation() {
+ return this.correlation;
+ }
+
+ public void setCorrelation(Correlation correlation) {
+ this.correlation = correlation;
+ }
+
+ public List<String> getRemoteFields() {
+ return this.remoteFields;
+ }
+
+ public void setRemoteFields(List<String> remoteFields) {
+ this.remoteFields = remoteFields;
+ }
+
+ public static class Correlation {
+
+ /**
+ * Whether to enable correlation of the baggage context with
logging contexts.
+ */
+ private boolean enabled = true;
+
+ /**
+ * List of fields that should be correlated with the logging
context. That
+ * means that these fields would end up as key-value pairs in e.g.
MDC.
+ */
+ private List<String> fields = new ArrayList<>();
+
+ public boolean isEnabled() {
+ return this.enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public List<String> getFields() {
+ return this.fields;
+ }
+
+ public void setFields(List<String> fields) {
+ this.fields = fields;
+ }
+
+ }
+
+ }
+
+ public static class Propagation {
+
+ /**
+ * Tracing context propagation type.
+ */
+ private PropagationType type = PropagationType.W3C;
+
+ public PropagationType getType() {
+ return this.type;
+ }
+
+ public void setType(PropagationType type) {
+ this.type = type;
+ }
+
+ public enum PropagationType {
+
+ /**
+ * B3 propagation type.
+ */
+ B3,
+
+ /**
+ * W3C propagation type.
+ */
+ W3C
+
+ }
+
+ }
+}
diff --git
a/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/resources/META-INF/spring-configuration-metadata.json
b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/resources/META-INF/spring-configuration-metadata.json
new file mode 100644
index 0000000000..3ae084b1f1
--- /dev/null
+++
b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/resources/META-INF/spring-configuration-metadata.json
@@ -0,0 +1,82 @@
+{
+ "groups": [
+ {
+ "name": "dubbo.tracing",
+ "type":
"org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties",
+ "sourceType":
"org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties"
+ },
+ {
+ "name": "dubbo.tracing.baggage",
+ "type":
"org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties$Baggage",
+ "sourceType":
"org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties",
+ "sourceMethod": "getBaggage()"
+ },
+ {
+ "name": "dubbo.tracing.baggage.correlation",
+ "type":
"org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties$Baggage$Correlation",
+ "sourceType":
"org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties$Baggage",
+ "sourceMethod": "getCorrelation()"
+ },
+ {
+ "name": "dubbo.tracing.propagation",
+ "type":
"org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties$Propagation",
+ "sourceType":
"org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties",
+ "sourceMethod": "getPropagation()"
+ },
+ {
+ "name": "dubbo.tracing.sampling",
+ "type":
"org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties$Sampling",
+ "sourceType":
"org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties",
+ "sourceMethod": "getSampling()"
+ }
+ ],
+ "properties": [
+ {
+ "name": "dubbo.tracing.baggage.correlation.enabled",
+ "type": "java.lang.Boolean",
+ "description": "Whether to enable correlation of the baggage context
with logging contexts.",
+ "sourceType":
"org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties$Baggage$Correlation",
+ "defaultValue": true
+ },
+ {
+ "name": "dubbo.tracing.baggage.correlation.fields",
+ "type": "java.util.List<java.lang.String>",
+ "description": "List of fields that should be correlated with the
logging context. That means that these fields would end up as key-value pairs
in e.g. MDC.",
+ "sourceType":
"org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties$Baggage$Correlation"
+ },
+ {
+ "name": "dubbo.tracing.baggage.enabled",
+ "type": "java.lang.Boolean",
+ "description": "Whether to enable Micrometer Tracing baggage
propagation.",
+ "sourceType":
"org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties$Baggage",
+ "defaultValue": true
+ },
+ {
+ "name": "dubbo.tracing.baggage.remote-fields",
+ "type": "java.util.List<java.lang.String>",
+ "description": "List of fields that are referenced the same in-process
as it is on the wire. For example, the field \"x-vcap-request-id\" would be set
as-is including the prefix.",
+ "sourceType":
"org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties$Baggage"
+ },
+ {
+ "name": "dubbo.tracing.enabled",
+ "type": "java.lang.Boolean",
+ "description": "Whether auto-configuration of tracing is enabled.",
+ "sourceType":
"org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties",
+ "defaultValue": true
+ },
+ {
+ "name": "dubbo.tracing.propagation.type",
+ "type":
"org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties$Propagation$PropagationType",
+ "description": "Tracing context propagation type.",
+ "sourceType":
"org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties$Propagation"
+ },
+ {
+ "name": "dubbo.tracing.sampling.probability",
+ "type": "java.lang.Float",
+ "description": "Probability in the range from 0.0 to 1.0 that a trace
will be sampled.",
+ "sourceType":
"org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties$Sampling",
+ "defaultValue": 0.1
+ }
+ ],
+ "hints": []
+}
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/src/main/resources/META-INF/spring.factories
new file mode 100644
index 0000000000..b7a570ea76
--- /dev/null
+++
b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,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
+
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/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 0000000000..9d3769fc9c
--- /dev/null
+++
b/dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1,4 @@
+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
diff --git a/dubbo-spring-boot/pom.xml b/dubbo-spring-boot/pom.xml
index 4c43c07955..2d6991aac4 100644
--- a/dubbo-spring-boot/pom.xml
+++ b/dubbo-spring-boot/pom.xml
@@ -36,6 +36,7 @@
<module>dubbo-spring-boot-autoconfigure</module>
<module>dubbo-spring-boot-compatible</module>
<module>dubbo-spring-boot-starter</module>
+ <module>dubbo-spring-boot-observability-starter</module>
</modules>
<properties>
@@ -45,6 +46,7 @@
<log4j2_version>2.19.0</log4j2_version>
<!-- Spring boot buddy is lower than the delivery dependency package
version and can only show the defined dependency version -->
<byte-buddy.version>1.13.0</byte-buddy.version>
+ <micrometer-core.version>1.10.4</micrometer-core.version>
</properties>
<dependencyManagement>
@@ -57,6 +59,11 @@
<type>pom</type>
<scope>import</scope>
</dependency>
+ <dependency>
+ <groupId>io.micrometer</groupId>
+ <artifactId>micrometer-core</artifactId>
+ <version>${micrometer-core.version}</version>
+ </dependency>
</dependencies>
</dependencyManagement>
diff --git a/dubbo-test/dubbo-dependencies-all/pom.xml
b/dubbo-test/dubbo-dependencies-all/pom.xml
index 5e9a515d5a..90e91d7e4d 100644
--- a/dubbo-test/dubbo-dependencies-all/pom.xml
+++ b/dubbo-test/dubbo-dependencies-all/pom.xml
@@ -318,6 +318,11 @@
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-spring-boot-observability-starter</artifactId>
+ </dependency>
+
<!-- test -->
<dependency>
<groupId>org.apache.dubbo</groupId>