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 @@
-
- org.apache.dubbo
- dubbo-metrics-default
-
io.micrometer
micrometer-tracing-bridge-otel
+
+ org.apache.dubbo
+ dubbo-spring-boot-observability-starter
+
+
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 @@
-
- org.apache.dubbo
- dubbo-metrics-default
-
io.micrometer
micrometer-tracing-bridge-otel
+
+ org.apache.dubbo
+ dubbo-spring-boot-observability-starter
+
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 @@
8
8
true
+ 2.7.8
2.7.8
+ 1.10.4
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring-boot.version}
+ pom
+ import
+
+
+ io.micrometer
+ micrometer-core
+ ${micrometer-core.version}
+
+
+
+
+
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 @@
1.8.0
0.1.35
1.10.4
+
1.0.2
3.3
0.16.0
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 @@
pom
${project.version}
+
+ org.apache.dubbo
+ dubbo-spring-boot-observability-starter
+ ${project.version}
+
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 @@
+
+
+
+
+ org.apache.dubbo
+ dubbo-spring-boot
+ ${revision}
+ ../pom.xml
+
+ 4.0.0
+
+ dubbo-spring-boot-observability-starter
+
+
+
+ io.micrometer
+ micrometer-tracing
+
+
+ io.micrometer
+ micrometer-observation
+
+
+ io.micrometer
+ micrometer-core
+
+
+ org.springframework.boot
+ spring-boot-autoconfigure
+ true
+
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+ true
+
+
+ org.apache.dubbo
+ dubbo-common
+ ${project.version}
+ true
+
+
+ io.micrometer
+ micrometer-tracing-bridge-otel
+ true
+
+
+ io.micrometer
+ micrometer-tracing-bridge-brave
+ true
+
+
+ org.apache.dubbo
+ dubbo-metrics-default
+ ${project.version}
+
+
+
+
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,
+ ObjectProvider> 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 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> categories;
+
+ ObservationHandlerGrouping(Class extends ObservationHandler> category) {
+ this(Collections.singletonList(category));
+ }
+
+ ObservationHandlerGrouping(List> categories) {
+ this.categories = categories;
+ }
+
+ void apply(List> handlers, ObservationRegistry.ObservationConfig config) {
+ MultiValueMap, 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> 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;
+ private final ObjectProvider> observationHandlers;
+
+ public ObservationRegistryPostProcessor(ObjectProvider observationHandlerGrouping,
+ ObjectProvider> 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> 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 predicates,
+ ObjectProvider reporters, ObjectProvider 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 spanHandlers,
+ List 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 scopeDecorators,
+ List 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 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 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 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 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 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 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 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 spanExporters,
+ ObjectProvider spanExportingPredicates, ObjectProvider spanReporters,
+ ObjectProvider 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 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 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 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 listeners;
+
+ OTelEventPublisher(List 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 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 getRemoteFields() {
+ return this.remoteFields;
+ }
+
+ public void setRemoteFields(List 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 fields = new ArrayList<>();
+
+ public boolean isEnabled() {
+ return this.enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public List getFields() {
+ return this.fields;
+ }
+
+ public void setFields(List 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",
+ "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",
+ "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 @@
dubbo-spring-boot-autoconfigure
dubbo-spring-boot-compatible
dubbo-spring-boot-starter
+ dubbo-spring-boot-observability-starter
@@ -45,6 +46,7 @@
2.19.0
1.13.0
+ 1.10.4
@@ -57,6 +59,11 @@
pom
import
+
+ io.micrometer
+ micrometer-core
+ ${micrometer-core.version}
+
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 @@
dubbo-spring-boot-starter
+
+ org.apache.dubbo
+ dubbo-spring-boot-observability-starter
+
+
org.apache.dubbo