From 34981c9606facf63000264a71d2a69b93afe2fd1 Mon Sep 17 00:00:00 2001 From: ShenFeng312 <49786112+ShenFeng312@users.noreply.github.com> Date: Thu, 2 Mar 2023 06:37:06 +0800 Subject: [PATCH] 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 +- .../consumer/ObservationConfiguration.java | 215 --------------- .../dubbo-demo-spring-boot-provider/pom.xml | 8 +- .../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 +++ ...bboMicrometerTracingAutoConfiguration.java | 78 ++++++ .../DubboObservationAutoConfiguration.java | 153 ++++++++++ .../ObservationHandlerGrouping.java | 74 +++++ .../ObservationRegistryPostProcessor.java | 54 ++++ .../brave/BraveAutoConfiguration.java | 261 ++++++++++++++++++ .../otel/OpenTelemetryAutoConfiguration.java | 257 +++++++++++++++++ .../config/DubboTracingProperties.java | 191 +++++++++++++ .../spring-configuration-metadata.json | 82 ++++++ .../main/resources/META-INF/spring.factories | 6 + ...ot.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(-) delete mode 100644 dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-consumer/src/main/java/org/apache/dubbo/springboot/demo/consumer/ObservationConfiguration.java delete mode 100644 dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-provider/src/main/java/org/apache/dubbo/springboot/demo/provider/ObservationConfiguration.java create mode 100644 dubbo-spring-boot/dubbo-spring-boot-observability-starter/pom.xml create mode 100644 dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/annotation/ConditionalOnDubboTracingEnable.java create mode 100644 dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/DubboMicrometerTracingAutoConfiguration.java create mode 100644 dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/DubboObservationAutoConfiguration.java create mode 100644 dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservationHandlerGrouping.java create mode 100644 dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservationRegistryPostProcessor.java create mode 100644 dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/brave/BraveAutoConfiguration.java create mode 100644 dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/otel/OpenTelemetryAutoConfiguration.java create mode 100644 dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/java/org/apache/dubbo/spring/boot/observability/config/DubboTracingProperties.java create mode 100644 dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/resources/META-INF/spring-configuration-metadata.json create mode 100644 dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/resources/META-INF/spring.factories create mode 100644 dubbo-spring-boot/dubbo-spring-boot-observability-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 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 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 category = findCategory(handler); + if (category != null) { + groupings.add(category, handler); + } else { + config.observationHandler(handler); + } + } + for (Class category : this.categories) { + List> handlerGroup = groupings.get(category); + if (!CollectionUtils.isEmpty(handlerGroup)) { + config.observationHandler(new ObservationHandler.FirstMatchingCompositeObservationHandler(handlerGroup)); + } + } + } + + private Class findCategory(ObservationHandler handler) { + for (Class 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