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
This commit is contained in:
parent
dc74f131a7
commit
34981c9606
|
|
@ -134,15 +134,16 @@
|
|||
</dependency>
|
||||
|
||||
<!-- Observabililty -->
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-metrics-default</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micrometer</groupId>
|
||||
<artifactId>micrometer-tracing-bridge-otel</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-spring-boot-observability-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
|||
|
|
@ -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("=================");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -133,14 +133,14 @@
|
|||
</dependency>
|
||||
|
||||
<!-- Observability -->
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-metrics-default</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micrometer</groupId>
|
||||
<artifactId>micrometer-tracing-bridge-otel</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-spring-boot-observability-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
|
|
|||
|
|
@ -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("=================");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -36,7 +36,27 @@
|
|||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<skip_maven_deploy>true</skip_maven_deploy>
|
||||
<spring-boot.version>2.7.8</spring-boot.version>
|
||||
<spring-boot-maven-plugin.version>2.7.8</spring-boot-maven-plugin.version>
|
||||
<micrometer-core.version>1.10.4</micrometer-core.version>
|
||||
</properties>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>${spring-boot.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micrometer</groupId>
|
||||
<artifactId>micrometer-core</artifactId>
|
||||
<version>${micrometer-core.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</dependencyManagement>
|
||||
|
||||
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -135,6 +135,7 @@
|
|||
<protostuff_version>1.8.0</protostuff_version>
|
||||
<envoy_api_version>0.1.35</envoy_api_version>
|
||||
<micrometer.version>1.10.4</micrometer.version>
|
||||
|
||||
<micrometer-tracing.version>1.0.2</micrometer-tracing.version>
|
||||
<t_digest.version>3.3</t_digest.version>
|
||||
<prometheus_client.version>0.16.0</prometheus_client.version>
|
||||
|
|
|
|||
|
|
@ -487,6 +487,11 @@
|
|||
<type>pom</type>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-spring-boot-observability-starter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- test -->
|
||||
<dependency>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-spring-boot</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>dubbo-spring-boot-observability-starter</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.micrometer</groupId>
|
||||
<artifactId>micrometer-tracing</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micrometer</groupId>
|
||||
<artifactId>micrometer-observation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micrometer</groupId>
|
||||
<artifactId>micrometer-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-common</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micrometer</groupId>
|
||||
<artifactId>micrometer-tracing-bridge-otel</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micrometer</groupId>
|
||||
<artifactId>micrometer-tracing-bridge-brave</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-metrics-default</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
@ -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 {
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.spring.boot.observability.autoconfigure;
|
||||
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.observation.DefaultMeterObservationHandler;
|
||||
import io.micrometer.core.instrument.observation.MeterObservationHandler;
|
||||
import io.micrometer.observation.Observation;
|
||||
import io.micrometer.observation.ObservationHandler;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import io.micrometer.tracing.Tracer;
|
||||
import io.micrometer.tracing.handler.TracingAwareMeterObservationHandler;
|
||||
import io.micrometer.tracing.handler.TracingObservationHandler;
|
||||
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||
import org.apache.dubbo.spring.boot.observability.annotation.ConditionalOnDubboTracingEnable;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Register observationRegistry to ApplicationModel.
|
||||
* Create observationRegistry when you are using Boot <3.0 or you are not using spring-boot-starter-actuator
|
||||
*/
|
||||
@AutoConfiguration(after =DubboMicrometerTracingAutoConfiguration.class,afterName = "org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration")
|
||||
@ConditionalOnDubboTracingEnable
|
||||
public class DubboObservationAutoConfiguration implements BeanFactoryAware, SmartInitializingSingleton {
|
||||
|
||||
public DubboObservationAutoConfiguration(ApplicationModel applicationModel) {
|
||||
this.applicationModel = applicationModel;
|
||||
}
|
||||
|
||||
private final ApplicationModel applicationModel;
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
ObservationRegistry observationRegistry() {
|
||||
return ObservationRegistry.create();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(type = "org.springframework.boot.actuate.autoconfigure.observation.ObservationRegistryPostProcessor")
|
||||
public ObservationRegistryPostProcessor dubboObservationRegistryPostProcessor(ObjectProvider<ObservationHandlerGrouping> observationHandlerGrouping,
|
||||
ObjectProvider<ObservationHandler<?>> observationHandlers) {
|
||||
return new ObservationRegistryPostProcessor(observationHandlerGrouping, observationHandlers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterSingletonsInstantiated() {
|
||||
applicationModel.getBeanFactory().registerBean(beanFactory.getBean(ObservationRegistry.class));
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(MeterRegistry.class)
|
||||
@ConditionalOnMissingClass("io.micrometer.tracing.Tracer")
|
||||
@ConditionalOnMissingBean(type = "org.springframework.boot.actuate.autoconfigure.observation.ObservationRegistryPostProcessor")
|
||||
static class OnlyMetricsConfiguration {
|
||||
|
||||
@Bean
|
||||
ObservationHandlerGrouping metricsObservationHandlerGrouping() {
|
||||
return new ObservationHandlerGrouping(MeterObservationHandler.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(Tracer.class)
|
||||
@ConditionalOnMissingClass("io.micrometer.core.instrument.MeterRegistry")
|
||||
@ConditionalOnMissingBean(type = "org.springframework.boot.actuate.autoconfigure.observation.ObservationRegistryPostProcessor")
|
||||
static class OnlyTracingConfiguration {
|
||||
|
||||
@Bean
|
||||
ObservationHandlerGrouping tracingObservationHandlerGrouping() {
|
||||
return new ObservationHandlerGrouping(TracingObservationHandler.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ MeterRegistry.class, Tracer.class })
|
||||
@ConditionalOnMissingBean(type = "org.springframework.boot.actuate.autoconfigure.observation.ObservationRegistryPostProcessor")
|
||||
static class MetricsWithTracingConfiguration {
|
||||
|
||||
@Bean
|
||||
ObservationHandlerGrouping metricsAndTracingObservationHandlerGrouping() {
|
||||
return new ObservationHandlerGrouping(
|
||||
Arrays.asList(TracingObservationHandler.class, MeterObservationHandler.class));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnBean(MeterRegistry.class)
|
||||
@ConditionalOnMissingBean(MeterObservationHandler.class)
|
||||
static class MeterObservationHandlerConfiguration {
|
||||
|
||||
@ConditionalOnMissingBean(type = "io.micrometer.tracing.Tracer")
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class OnlyMetricsMeterObservationHandlerConfiguration {
|
||||
|
||||
@Bean
|
||||
DefaultMeterObservationHandler defaultMeterObservationHandler(MeterRegistry meterRegistry) {
|
||||
return new DefaultMeterObservationHandler(meterRegistry);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnBean(Tracer.class)
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class TracingAndMetricsObservationHandlerConfiguration {
|
||||
|
||||
@Bean
|
||||
TracingAwareMeterObservationHandler<Observation.Context> tracingAwareMeterObservationHandler(
|
||||
MeterRegistry meterRegistry, Tracer tracer) {
|
||||
DefaultMeterObservationHandler delegate = new DefaultMeterObservationHandler(meterRegistry);
|
||||
return new TracingAwareMeterObservationHandler<>(delegate, tracer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.spring.boot.observability.autoconfigure;
|
||||
|
||||
import io.micrometer.observation.ObservationHandler;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Groups {@link ObservationHandler ObservationHandlers} by type.
|
||||
* copy from {@link org.springframework.boot.actuate.autoconfigure.observation.ObservationHandlerGrouping}
|
||||
* this class is available starting from Boot 3.0. It's not available if you're using Boot < 3.0
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class ObservationHandlerGrouping {
|
||||
|
||||
private final List<Class<? extends ObservationHandler>> categories;
|
||||
|
||||
ObservationHandlerGrouping(Class<? extends ObservationHandler> category) {
|
||||
this(Collections.singletonList(category));
|
||||
}
|
||||
|
||||
ObservationHandlerGrouping(List<Class<? extends ObservationHandler>> categories) {
|
||||
this.categories = categories;
|
||||
}
|
||||
|
||||
void apply(List<ObservationHandler<?>> handlers, ObservationRegistry.ObservationConfig config) {
|
||||
MultiValueMap<Class<? extends ObservationHandler>, ObservationHandler<?>> groupings = new LinkedMultiValueMap<>();
|
||||
for (ObservationHandler<?> handler : handlers) {
|
||||
Class<? extends ObservationHandler> category = findCategory(handler);
|
||||
if (category != null) {
|
||||
groupings.add(category, handler);
|
||||
} else {
|
||||
config.observationHandler(handler);
|
||||
}
|
||||
}
|
||||
for (Class<? extends ObservationHandler> category : this.categories) {
|
||||
List<ObservationHandler<?>> handlerGroup = groupings.get(category);
|
||||
if (!CollectionUtils.isEmpty(handlerGroup)) {
|
||||
config.observationHandler(new ObservationHandler.FirstMatchingCompositeObservationHandler(handlerGroup));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Class<? extends ObservationHandler> findCategory(ObservationHandler<?> handler) {
|
||||
for (Class<? extends ObservationHandler> category : this.categories) {
|
||||
if (category.isInstance(handler)) {
|
||||
return category;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.spring.boot.observability.autoconfigure;
|
||||
|
||||
import io.micrometer.observation.ObservationHandler;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* registry observationHandlers to observationConfig
|
||||
*/
|
||||
public class ObservationRegistryPostProcessor implements BeanPostProcessor {
|
||||
private final ObjectProvider<ObservationHandlerGrouping> observationHandlerGrouping;
|
||||
private final ObjectProvider<ObservationHandler<?>> observationHandlers;
|
||||
|
||||
public ObservationRegistryPostProcessor(ObjectProvider<ObservationHandlerGrouping> observationHandlerGrouping,
|
||||
ObjectProvider<ObservationHandler<?>> observationHandlers){
|
||||
this.observationHandlerGrouping = observationHandlerGrouping;
|
||||
this.observationHandlers = observationHandlers;
|
||||
|
||||
}
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
if(bean instanceof ObservationRegistry){
|
||||
ObservationRegistry observationRegistry = (ObservationRegistry) bean;
|
||||
List<ObservationHandler<?>> observationHandlerList =
|
||||
observationHandlers.orderedStream().collect(Collectors.toList());
|
||||
observationHandlerGrouping.ifAvailable(grouping->{
|
||||
grouping.apply(observationHandlerList,
|
||||
observationRegistry.observationConfig());
|
||||
});
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,261 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.spring.boot.observability.autoconfigure.brave;
|
||||
|
||||
import brave.CurrentSpanCustomizer;
|
||||
import brave.SpanCustomizer;
|
||||
import brave.Tracing;
|
||||
import brave.TracingCustomizer;
|
||||
import brave.baggage.BaggageField;
|
||||
import brave.baggage.BaggagePropagation;
|
||||
import brave.baggage.BaggagePropagationConfig;
|
||||
import brave.baggage.BaggagePropagationCustomizer;
|
||||
import brave.baggage.CorrelationScopeConfig;
|
||||
import brave.baggage.CorrelationScopeCustomizer;
|
||||
import brave.baggage.CorrelationScopeDecorator;
|
||||
import brave.context.slf4j.MDCScopeDecorator;
|
||||
import brave.handler.SpanHandler;
|
||||
import brave.propagation.B3Propagation;
|
||||
import brave.propagation.CurrentTraceContext;
|
||||
import brave.propagation.CurrentTraceContextCustomizer;
|
||||
import brave.propagation.Propagation;
|
||||
import brave.propagation.ThreadLocalCurrentTraceContext;
|
||||
import brave.sampler.Sampler;
|
||||
import io.micrometer.tracing.Tracer;
|
||||
import io.micrometer.tracing.brave.bridge.BraveBaggageManager;
|
||||
import io.micrometer.tracing.brave.bridge.BraveCurrentTraceContext;
|
||||
import io.micrometer.tracing.brave.bridge.BravePropagator;
|
||||
import io.micrometer.tracing.brave.bridge.BraveSpanCustomizer;
|
||||
import io.micrometer.tracing.brave.bridge.BraveTracer;
|
||||
import io.micrometer.tracing.brave.bridge.CompositeSpanHandler;
|
||||
import io.micrometer.tracing.brave.bridge.W3CPropagation;
|
||||
import io.micrometer.tracing.exporter.SpanExportingPredicate;
|
||||
import io.micrometer.tracing.exporter.SpanFilter;
|
||||
import io.micrometer.tracing.exporter.SpanReporter;
|
||||
import org.apache.dubbo.spring.boot.observability.annotation.ConditionalOnDubboTracingEnable;
|
||||
import org.apache.dubbo.spring.boot.observability.autoconfigure.DubboMicrometerTracingAutoConfiguration;
|
||||
import org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* provider Brave when you are using Boot <3.0 or you are not using spring-boot-starter-actuator
|
||||
*/
|
||||
@AutoConfiguration(before = DubboMicrometerTracingAutoConfiguration.class, afterName = "org.springframework.boot.actuate.autoconfigure.tracing.BraveAutoConfiguration")
|
||||
@ConditionalOnClass({Tracer.class, BraveTracer.class})
|
||||
@EnableConfigurationProperties(DubboTracingProperties.class)
|
||||
@ConditionalOnDubboTracingEnable
|
||||
public class BraveAutoConfiguration {
|
||||
|
||||
private static final BraveBaggageManager BRAVE_BAGGAGE_MANAGER = new BraveBaggageManager();
|
||||
|
||||
/**
|
||||
* Default value for application name if {@code spring.application.name} is not set.
|
||||
*/
|
||||
private static final String DEFAULT_APPLICATION_NAME = "application";
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
CompositeSpanHandler compositeSpanHandler(ObjectProvider<SpanExportingPredicate> predicates,
|
||||
ObjectProvider<SpanReporter> reporters, ObjectProvider<SpanFilter> filters) {
|
||||
return new CompositeSpanHandler(predicates.orderedStream().collect(Collectors.toList()),
|
||||
reporters.orderedStream().collect(Collectors.toList()),
|
||||
filters.orderedStream().collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Tracing braveTracing(Environment environment, List<SpanHandler> spanHandlers,
|
||||
List<TracingCustomizer> tracingCustomizers, CurrentTraceContext currentTraceContext,
|
||||
Propagation.Factory propagationFactory, Sampler sampler) {
|
||||
String applicationName = environment.getProperty("spring.application.name", DEFAULT_APPLICATION_NAME);
|
||||
Tracing.Builder builder = Tracing.newBuilder().currentTraceContext(currentTraceContext).traceId128Bit(true)
|
||||
.supportsJoin(false).propagationFactory(propagationFactory).sampler(sampler)
|
||||
.localServiceName(applicationName);
|
||||
spanHandlers.forEach(builder::addSpanHandler);
|
||||
for (TracingCustomizer tracingCustomizer : tracingCustomizers) {
|
||||
tracingCustomizer.customize(builder);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public brave.Tracer braveTracer(Tracing tracing) {
|
||||
return tracing.tracer();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public CurrentTraceContext braveCurrentTraceContext(List<CurrentTraceContext.ScopeDecorator> scopeDecorators,
|
||||
List<CurrentTraceContextCustomizer> currentTraceContextCustomizers) {
|
||||
ThreadLocalCurrentTraceContext.Builder builder = ThreadLocalCurrentTraceContext.newBuilder();
|
||||
scopeDecorators.forEach(builder::addScopeDecorator);
|
||||
for (CurrentTraceContextCustomizer currentTraceContextCustomizer : currentTraceContextCustomizers) {
|
||||
currentTraceContextCustomizer.customize(builder);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Sampler braveSampler(DubboTracingProperties properties) {
|
||||
return Sampler.create(properties.getSampling().getProbability());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(io.micrometer.tracing.Tracer.class)
|
||||
BraveTracer braveTracerBridge(brave.Tracer tracer, CurrentTraceContext currentTraceContext) {
|
||||
return new BraveTracer(tracer, new BraveCurrentTraceContext(currentTraceContext), BRAVE_BAGGAGE_MANAGER);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
BravePropagator bravePropagator(Tracing tracing) {
|
||||
return new BravePropagator(tracing);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(SpanCustomizer.class)
|
||||
CurrentSpanCustomizer currentSpanCustomizer(Tracing tracing) {
|
||||
return CurrentSpanCustomizer.create(tracing);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(io.micrometer.tracing.SpanCustomizer.class)
|
||||
BraveSpanCustomizer braveSpanCustomizer(SpanCustomizer spanCustomizer) {
|
||||
return new BraveSpanCustomizer(spanCustomizer);
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnProperty(value = "dubbo.tracing.baggage.enabled", havingValue = "false")
|
||||
static class BraveNoBaggageConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
Propagation.Factory propagationFactory(DubboTracingProperties tracing) {
|
||||
DubboTracingProperties.Propagation.PropagationType type = tracing.getPropagation().getType();
|
||||
switch (type) {
|
||||
case B3:
|
||||
return B3Propagation.newFactoryBuilder().injectFormat(B3Propagation.Format.SINGLE_NO_PARENT).build();
|
||||
case W3C:
|
||||
return new W3CPropagation();
|
||||
default:
|
||||
throw new IllegalArgumentException("UnSupport propagation type");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(value = "dubbo.tracing.baggage.enabled", matchIfMissing = true)
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class BraveBaggageConfiguration {
|
||||
private final DubboTracingProperties dubboTracingProperties;
|
||||
|
||||
public BraveBaggageConfiguration(DubboTracingProperties dubboTracingProperties) {
|
||||
this.dubboTracingProperties = dubboTracingProperties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnProperty(prefix = "dubbo.tracing.propagation", value = "type", havingValue = "B3")
|
||||
BaggagePropagation.FactoryBuilder b3PropagationFactoryBuilder(
|
||||
ObjectProvider<BaggagePropagationCustomizer> baggagePropagationCustomizers) {
|
||||
Propagation.Factory delegate =
|
||||
B3Propagation.newFactoryBuilder().injectFormat(B3Propagation.Format.SINGLE_NO_PARENT).build();
|
||||
|
||||
BaggagePropagation.FactoryBuilder builder = BaggagePropagation.newFactoryBuilder(delegate);
|
||||
baggagePropagationCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnProperty(prefix = "dubbo.tracing.propagation", value = "type", havingValue = "W3C", matchIfMissing = true)
|
||||
BaggagePropagation.FactoryBuilder w3cPropagationFactoryBuilder(
|
||||
ObjectProvider<BaggagePropagationCustomizer> baggagePropagationCustomizers) {
|
||||
Propagation.Factory delegate = new W3CPropagation(BRAVE_BAGGAGE_MANAGER, Collections.emptyList());
|
||||
|
||||
BaggagePropagation.FactoryBuilder builder = BaggagePropagation.newFactoryBuilder(delegate);
|
||||
baggagePropagationCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@Order(0)
|
||||
BaggagePropagationCustomizer remoteFieldsBaggagePropagationCustomizer() {
|
||||
return (builder) -> {
|
||||
List<String> remoteFields = dubboTracingProperties.getBaggage().getRemoteFields();
|
||||
for (String fieldName : remoteFields) {
|
||||
builder.add(BaggagePropagationConfig.SingleBaggageField.remote(BaggageField.create(fieldName)));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
Propagation.Factory propagationFactory(BaggagePropagation.FactoryBuilder factoryBuilder) {
|
||||
return factoryBuilder.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
CorrelationScopeDecorator.Builder mdcCorrelationScopeDecoratorBuilder(
|
||||
ObjectProvider<CorrelationScopeCustomizer> correlationScopeCustomizers) {
|
||||
CorrelationScopeDecorator.Builder builder = MDCScopeDecorator.newBuilder();
|
||||
correlationScopeCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(0)
|
||||
@ConditionalOnProperty(prefix = "dubbo.tracing.baggage.correlation", name = "enabled",
|
||||
matchIfMissing = true)
|
||||
CorrelationScopeCustomizer correlationFieldsCorrelationScopeCustomizer() {
|
||||
return (builder) -> {
|
||||
List<String> correlationFields = this.dubboTracingProperties.getBaggage().getCorrelation().getFields();
|
||||
for (String field : correlationFields) {
|
||||
builder.add(CorrelationScopeConfig.SingleCorrelationField.newBuilder(BaggageField.create(field))
|
||||
.flushOnUpdate().build());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(CurrentTraceContext.ScopeDecorator.class)
|
||||
CurrentTraceContext.ScopeDecorator correlationScopeDecorator(CorrelationScopeDecorator.Builder builder) {
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,257 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.spring.boot.observability.autoconfigure.otel;
|
||||
|
||||
import io.micrometer.tracing.SpanCustomizer;
|
||||
import io.micrometer.tracing.exporter.SpanExportingPredicate;
|
||||
import io.micrometer.tracing.exporter.SpanFilter;
|
||||
import io.micrometer.tracing.exporter.SpanReporter;
|
||||
import io.micrometer.tracing.otel.bridge.CompositeSpanExporter;
|
||||
import io.micrometer.tracing.otel.bridge.EventListener;
|
||||
import io.micrometer.tracing.otel.bridge.EventPublishingContextWrapper;
|
||||
import io.micrometer.tracing.otel.bridge.OtelBaggageManager;
|
||||
import io.micrometer.tracing.otel.bridge.OtelCurrentTraceContext;
|
||||
import io.micrometer.tracing.otel.bridge.OtelPropagator;
|
||||
import io.micrometer.tracing.otel.bridge.OtelSpanCustomizer;
|
||||
import io.micrometer.tracing.otel.bridge.OtelTracer;
|
||||
import io.micrometer.tracing.otel.bridge.Slf4JBaggageEventListener;
|
||||
import io.micrometer.tracing.otel.bridge.Slf4JEventListener;
|
||||
import io.micrometer.tracing.otel.propagation.BaggageTextMapPropagator;
|
||||
import io.opentelemetry.api.OpenTelemetry;
|
||||
import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator;
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.api.trace.Tracer;
|
||||
import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator;
|
||||
import io.opentelemetry.context.ContextStorage;
|
||||
import io.opentelemetry.context.propagation.ContextPropagators;
|
||||
import io.opentelemetry.context.propagation.TextMapPropagator;
|
||||
import io.opentelemetry.extension.trace.propagation.B3Propagator;
|
||||
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||
import io.opentelemetry.sdk.resources.Resource;
|
||||
import io.opentelemetry.sdk.trace.SdkTracerProvider;
|
||||
import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder;
|
||||
import io.opentelemetry.sdk.trace.SpanProcessor;
|
||||
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
|
||||
import io.opentelemetry.sdk.trace.export.SpanExporter;
|
||||
import io.opentelemetry.sdk.trace.samplers.Sampler;
|
||||
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
|
||||
import org.apache.dubbo.common.Version;
|
||||
import org.apache.dubbo.spring.boot.observability.annotation.ConditionalOnDubboTracingEnable;
|
||||
import org.apache.dubbo.spring.boot.observability.autoconfigure.DubboMicrometerTracingAutoConfiguration;
|
||||
import org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* provider OpenTelemetry when you are using Boot <3.0 or you are not using spring-boot-starter-actuator
|
||||
*/
|
||||
@AutoConfiguration(before = DubboMicrometerTracingAutoConfiguration.class, afterName = "org.springframework.boot.actuate.autoconfigure.tracing.OpenTelemetryAutoConfiguration")
|
||||
@ConditionalOnDubboTracingEnable
|
||||
@ConditionalOnClass({OtelTracer.class, SdkTracerProvider.class, OpenTelemetry.class})
|
||||
@EnableConfigurationProperties(DubboTracingProperties.class)
|
||||
public class OpenTelemetryAutoConfiguration {
|
||||
|
||||
/**
|
||||
* Default value for application name if {@code spring.application.name} is not set.
|
||||
*/
|
||||
private static final String DEFAULT_APPLICATION_NAME = "application";
|
||||
|
||||
private final DubboTracingProperties dubboTracingProperties;
|
||||
|
||||
OpenTelemetryAutoConfiguration(DubboTracingProperties dubboTracingProperties) {
|
||||
this.dubboTracingProperties = dubboTracingProperties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
OpenTelemetry openTelemetry(SdkTracerProvider sdkTracerProvider, ContextPropagators contextPropagators) {
|
||||
return OpenTelemetrySdk.builder().setTracerProvider(sdkTracerProvider).setPropagators(contextPropagators)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
SdkTracerProvider otelSdkTracerProvider(Environment environment, ObjectProvider<SpanProcessor> spanProcessors,
|
||||
Sampler sampler) {
|
||||
String applicationName = environment.getProperty("spring.application.name", DEFAULT_APPLICATION_NAME);
|
||||
SdkTracerProviderBuilder builder = SdkTracerProvider.builder().setSampler(sampler)
|
||||
.setResource(Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, applicationName)));
|
||||
spanProcessors.orderedStream().forEach(builder::addSpanProcessor);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
ContextPropagators otelContextPropagators(ObjectProvider<TextMapPropagator> textMapPropagators) {
|
||||
return ContextPropagators.create(TextMapPropagator.composite(textMapPropagators.orderedStream().collect(Collectors.toList())));
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
Sampler otelSampler() {
|
||||
Sampler rootSampler = Sampler.traceIdRatioBased(this.dubboTracingProperties.getSampling().getProbability());
|
||||
return Sampler.parentBased(rootSampler);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
SpanProcessor otelSpanProcessor(ObjectProvider<SpanExporter> spanExporters,
|
||||
ObjectProvider<SpanExportingPredicate> spanExportingPredicates, ObjectProvider<SpanReporter> spanReporters,
|
||||
ObjectProvider<SpanFilter> spanFilters) {
|
||||
return BatchSpanProcessor.builder(new CompositeSpanExporter(spanExporters.orderedStream().collect(Collectors.toList()),
|
||||
spanExportingPredicates.orderedStream().collect(Collectors.toList()), spanReporters.orderedStream().collect(Collectors.toList()),
|
||||
spanFilters.orderedStream().collect(Collectors.toList()))).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
Tracer otelTracer(OpenTelemetry openTelemetry) {
|
||||
return openTelemetry.getTracer("org.apache.dubbo", Version.getVersion());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(io.micrometer.tracing.Tracer.class)
|
||||
OtelTracer micrometerOtelTracer(Tracer tracer, OtelTracer.EventPublisher eventPublisher,
|
||||
OtelCurrentTraceContext otelCurrentTraceContext) {
|
||||
return new OtelTracer(tracer, otelCurrentTraceContext, eventPublisher,
|
||||
new OtelBaggageManager(otelCurrentTraceContext, this.dubboTracingProperties.getBaggage().getRemoteFields(),
|
||||
Collections.emptyList()));
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
OtelPropagator otelPropagator(ContextPropagators contextPropagators, Tracer tracer) {
|
||||
return new OtelPropagator(contextPropagators, tracer);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
OtelTracer.EventPublisher otelTracerEventPublisher(List<EventListener> eventListeners) {
|
||||
return new OTelEventPublisher(eventListeners);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
OtelCurrentTraceContext otelCurrentTraceContext(OtelTracer.EventPublisher publisher) {
|
||||
ContextStorage.addWrapper(new EventPublishingContextWrapper(publisher));
|
||||
return new OtelCurrentTraceContext();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
Slf4JEventListener otelSlf4JEventListener() {
|
||||
return new Slf4JEventListener();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(SpanCustomizer.class)
|
||||
OtelSpanCustomizer otelSpanCustomizer() {
|
||||
return new OtelSpanCustomizer();
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnProperty(prefix = "dubbo.tracing.baggage", name = "enabled", matchIfMissing = true)
|
||||
static class BaggageConfiguration {
|
||||
|
||||
private final DubboTracingProperties tracingProperties;
|
||||
|
||||
BaggageConfiguration(DubboTracingProperties tracingProperties) {
|
||||
this.tracingProperties = tracingProperties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnProperty(prefix = "dubbo.tracing.propagation", name = "type", havingValue = "W3C",
|
||||
matchIfMissing = true)
|
||||
TextMapPropagator w3cTextMapPropagatorWithBaggage(OtelCurrentTraceContext otelCurrentTraceContext) {
|
||||
List<String> remoteFields = this.tracingProperties.getBaggage().getRemoteFields();
|
||||
return TextMapPropagator.composite(W3CTraceContextPropagator.getInstance(),
|
||||
W3CBaggagePropagator.getInstance(), new BaggageTextMapPropagator(remoteFields,
|
||||
new OtelBaggageManager(otelCurrentTraceContext, remoteFields, Collections.emptyList())));
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnProperty(prefix = "dubbo.tracing.propagation", name = "type", havingValue = "B3")
|
||||
TextMapPropagator b3BaggageTextMapPropagator(OtelCurrentTraceContext otelCurrentTraceContext) {
|
||||
List<String> remoteFields = this.tracingProperties.getBaggage().getRemoteFields();
|
||||
return TextMapPropagator.composite(B3Propagator.injectingSingleHeader(),
|
||||
new BaggageTextMapPropagator(remoteFields,
|
||||
new OtelBaggageManager(otelCurrentTraceContext, remoteFields, Collections.emptyList())));
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnProperty(prefix = "dubbo.tracing.baggage.correlation", name = "enabled",
|
||||
matchIfMissing = true)
|
||||
Slf4JBaggageEventListener otelSlf4JBaggageEventListener() {
|
||||
return new Slf4JBaggageEventListener(this.tracingProperties.getBaggage().getCorrelation().getFields());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnProperty(prefix = "dubbo.tracing.baggage", name = "enabled", havingValue = "false")
|
||||
static class NoBaggageConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnProperty(prefix = "dubbo.tracing.propagation", name = "type", havingValue = "B3")
|
||||
B3Propagator b3TextMapPropagator() {
|
||||
return B3Propagator.injectingSingleHeader();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnProperty(prefix = "dubbo.tracing.propagation", name = "type", havingValue = "W3C",
|
||||
matchIfMissing = true)
|
||||
W3CTraceContextPropagator w3cTextMapPropagatorWithoutBaggage() {
|
||||
return W3CTraceContextPropagator.getInstance();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class OTelEventPublisher implements OtelTracer.EventPublisher {
|
||||
|
||||
private final List<EventListener> listeners;
|
||||
|
||||
OTelEventPublisher(List<EventListener> listeners) {
|
||||
this.listeners = listeners;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishEvent(Object event) {
|
||||
for (EventListener listener : this.listeners) {
|
||||
listener.onEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.spring.boot.observability.config;
|
||||
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@ConfigurationProperties("dubbo.tracing")
|
||||
public class DubboTracingProperties {
|
||||
|
||||
/**
|
||||
* Whether auto-configuration of tracing is enabled.
|
||||
*/
|
||||
private boolean enabled = true;
|
||||
|
||||
/**
|
||||
* Sampling configuration.
|
||||
*/
|
||||
private final Sampling sampling = new Sampling();
|
||||
|
||||
/**
|
||||
* Baggage configuration.
|
||||
*/
|
||||
private final Baggage baggage = new Baggage();
|
||||
|
||||
/**
|
||||
* Propagation configuration.
|
||||
*/
|
||||
private final Propagation propagation = new Propagation();
|
||||
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public Sampling getSampling() {
|
||||
return this.sampling;
|
||||
}
|
||||
|
||||
public Baggage getBaggage() {
|
||||
return this.baggage;
|
||||
}
|
||||
|
||||
public Propagation getPropagation() {
|
||||
return this.propagation;
|
||||
}
|
||||
|
||||
public static class Sampling {
|
||||
|
||||
/**
|
||||
* Probability in the range from 0.0 to 1.0 that a trace will be sampled.
|
||||
*/
|
||||
private float probability = 0.10f;
|
||||
|
||||
public float getProbability() {
|
||||
return this.probability;
|
||||
}
|
||||
|
||||
public void setProbability(float probability) {
|
||||
this.probability = probability;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Baggage {
|
||||
|
||||
/**
|
||||
* Whether to enable Micrometer Tracing baggage propagation.
|
||||
*/
|
||||
private boolean enabled = true;
|
||||
|
||||
/**
|
||||
* Correlation configuration.
|
||||
*/
|
||||
private Correlation correlation = new Correlation();
|
||||
|
||||
/**
|
||||
* List of fields that are referenced the same in-process as it is on the wire.
|
||||
* For example, the field "x-vcap-request-id" would be set as-is including the
|
||||
* prefix.
|
||||
*/
|
||||
private List<String> remoteFields = new ArrayList<>();
|
||||
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public Correlation getCorrelation() {
|
||||
return this.correlation;
|
||||
}
|
||||
|
||||
public void setCorrelation(Correlation correlation) {
|
||||
this.correlation = correlation;
|
||||
}
|
||||
|
||||
public List<String> getRemoteFields() {
|
||||
return this.remoteFields;
|
||||
}
|
||||
|
||||
public void setRemoteFields(List<String> remoteFields) {
|
||||
this.remoteFields = remoteFields;
|
||||
}
|
||||
|
||||
public static class Correlation {
|
||||
|
||||
/**
|
||||
* Whether to enable correlation of the baggage context with logging contexts.
|
||||
*/
|
||||
private boolean enabled = true;
|
||||
|
||||
/**
|
||||
* List of fields that should be correlated with the logging context. That
|
||||
* means that these fields would end up as key-value pairs in e.g. MDC.
|
||||
*/
|
||||
private List<String> fields = new ArrayList<>();
|
||||
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public List<String> getFields() {
|
||||
return this.fields;
|
||||
}
|
||||
|
||||
public void setFields(List<String> fields) {
|
||||
this.fields = fields;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Propagation {
|
||||
|
||||
/**
|
||||
* Tracing context propagation type.
|
||||
*/
|
||||
private PropagationType type = PropagationType.W3C;
|
||||
|
||||
public PropagationType getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public void setType(PropagationType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public enum PropagationType {
|
||||
|
||||
/**
|
||||
* B3 propagation type.
|
||||
*/
|
||||
B3,
|
||||
|
||||
/**
|
||||
* W3C propagation type.
|
||||
*/
|
||||
W3C
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
{
|
||||
"groups": [
|
||||
{
|
||||
"name": "dubbo.tracing",
|
||||
"type": "org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties",
|
||||
"sourceType": "org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties"
|
||||
},
|
||||
{
|
||||
"name": "dubbo.tracing.baggage",
|
||||
"type": "org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties$Baggage",
|
||||
"sourceType": "org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties",
|
||||
"sourceMethod": "getBaggage()"
|
||||
},
|
||||
{
|
||||
"name": "dubbo.tracing.baggage.correlation",
|
||||
"type": "org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties$Baggage$Correlation",
|
||||
"sourceType": "org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties$Baggage",
|
||||
"sourceMethod": "getCorrelation()"
|
||||
},
|
||||
{
|
||||
"name": "dubbo.tracing.propagation",
|
||||
"type": "org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties$Propagation",
|
||||
"sourceType": "org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties",
|
||||
"sourceMethod": "getPropagation()"
|
||||
},
|
||||
{
|
||||
"name": "dubbo.tracing.sampling",
|
||||
"type": "org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties$Sampling",
|
||||
"sourceType": "org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties",
|
||||
"sourceMethod": "getSampling()"
|
||||
}
|
||||
],
|
||||
"properties": [
|
||||
{
|
||||
"name": "dubbo.tracing.baggage.correlation.enabled",
|
||||
"type": "java.lang.Boolean",
|
||||
"description": "Whether to enable correlation of the baggage context with logging contexts.",
|
||||
"sourceType": "org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties$Baggage$Correlation",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"name": "dubbo.tracing.baggage.correlation.fields",
|
||||
"type": "java.util.List<java.lang.String>",
|
||||
"description": "List of fields that should be correlated with the logging context. That means that these fields would end up as key-value pairs in e.g. MDC.",
|
||||
"sourceType": "org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties$Baggage$Correlation"
|
||||
},
|
||||
{
|
||||
"name": "dubbo.tracing.baggage.enabled",
|
||||
"type": "java.lang.Boolean",
|
||||
"description": "Whether to enable Micrometer Tracing baggage propagation.",
|
||||
"sourceType": "org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties$Baggage",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"name": "dubbo.tracing.baggage.remote-fields",
|
||||
"type": "java.util.List<java.lang.String>",
|
||||
"description": "List of fields that are referenced the same in-process as it is on the wire. For example, the field \"x-vcap-request-id\" would be set as-is including the prefix.",
|
||||
"sourceType": "org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties$Baggage"
|
||||
},
|
||||
{
|
||||
"name": "dubbo.tracing.enabled",
|
||||
"type": "java.lang.Boolean",
|
||||
"description": "Whether auto-configuration of tracing is enabled.",
|
||||
"sourceType": "org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"name": "dubbo.tracing.propagation.type",
|
||||
"type": "org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties$Propagation$PropagationType",
|
||||
"description": "Tracing context propagation type.",
|
||||
"sourceType": "org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties$Propagation"
|
||||
},
|
||||
{
|
||||
"name": "dubbo.tracing.sampling.probability",
|
||||
"type": "java.lang.Float",
|
||||
"description": "Probability in the range from 0.0 to 1.0 that a trace will be sampled.",
|
||||
"sourceType": "org.apache.dubbo.spring.boot.observability.config.DubboTracingProperties$Sampling",
|
||||
"defaultValue": 0.1
|
||||
}
|
||||
],
|
||||
"hints": []
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -36,6 +36,7 @@
|
|||
<module>dubbo-spring-boot-autoconfigure</module>
|
||||
<module>dubbo-spring-boot-compatible</module>
|
||||
<module>dubbo-spring-boot-starter</module>
|
||||
<module>dubbo-spring-boot-observability-starter</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
|
|
@ -45,6 +46,7 @@
|
|||
<log4j2_version>2.19.0</log4j2_version>
|
||||
<!-- Spring boot buddy is lower than the delivery dependency package version and can only show the defined dependency version -->
|
||||
<byte-buddy.version>1.13.0</byte-buddy.version>
|
||||
<micrometer-core.version>1.10.4</micrometer-core.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
|
|
@ -57,6 +59,11 @@
|
|||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micrometer</groupId>
|
||||
<artifactId>micrometer-core</artifactId>
|
||||
<version>${micrometer-core.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
|
|
|||
|
|
@ -318,6 +318,11 @@
|
|||
<artifactId>dubbo-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-spring-boot-observability-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- test -->
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
|
|
|
|||
Loading…
Reference in New Issue