|
|
|
@ -16,8 +16,14 @@
|
|
|
|
|
|
|
|
|
|
package org.springframework.boot.actuate.autoconfigure.tracing;
|
|
|
|
|
|
|
|
|
|
import java.time.Duration;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.Collection;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
import java.util.concurrent.CountDownLatch;
|
|
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
import java.util.concurrent.TimeoutException;
|
|
|
|
|
import java.util.stream.Stream;
|
|
|
|
|
|
|
|
|
|
import io.micrometer.tracing.SpanCustomizer;
|
|
|
|
@ -30,18 +36,26 @@ 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.common.AttributeKey;
|
|
|
|
|
import io.opentelemetry.api.common.Attributes;
|
|
|
|
|
import io.opentelemetry.api.trace.Tracer;
|
|
|
|
|
import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator;
|
|
|
|
|
import io.opentelemetry.context.propagation.ContextPropagators;
|
|
|
|
|
import io.opentelemetry.context.propagation.TextMapPropagator;
|
|
|
|
|
import io.opentelemetry.extension.trace.propagation.B3Propagator;
|
|
|
|
|
import io.opentelemetry.sdk.common.CompletableResultCode;
|
|
|
|
|
import io.opentelemetry.sdk.resources.Resource;
|
|
|
|
|
import io.opentelemetry.sdk.trace.SdkTracerProvider;
|
|
|
|
|
import io.opentelemetry.sdk.trace.SpanProcessor;
|
|
|
|
|
import io.opentelemetry.sdk.trace.data.SpanData;
|
|
|
|
|
import io.opentelemetry.sdk.trace.export.SpanExporter;
|
|
|
|
|
import io.opentelemetry.sdk.trace.samplers.Sampler;
|
|
|
|
|
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
|
|
|
|
|
import org.junit.jupiter.api.Test;
|
|
|
|
|
import org.junit.jupiter.params.ParameterizedTest;
|
|
|
|
|
import org.junit.jupiter.params.provider.ValueSource;
|
|
|
|
|
|
|
|
|
|
import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration;
|
|
|
|
|
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
|
|
|
|
import org.springframework.boot.test.context.FilteredClassLoader;
|
|
|
|
|
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
|
|
|
@ -143,6 +157,26 @@ class OpenTelemetryAutoConfigurationTests {
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void shouldSetupDefaultResourceAttributes() {
|
|
|
|
|
this.contextRunner
|
|
|
|
|
.withConfiguration(
|
|
|
|
|
AutoConfigurations.of(ObservationAutoConfiguration.class, MicrometerTracingAutoConfiguration.class))
|
|
|
|
|
.withUserConfiguration(InMemoryRecordingSpanExporterConfiguration.class)
|
|
|
|
|
.withPropertyValues("management.tracing.sampling.probability=1.0")
|
|
|
|
|
.run((context) -> {
|
|
|
|
|
context.getBean(io.micrometer.tracing.Tracer.class).nextSpan().name("test").end();
|
|
|
|
|
InMemoryRecordingSpanExporter exporter = context.getBean(InMemoryRecordingSpanExporter.class);
|
|
|
|
|
exporter.await(Duration.ofSeconds(10));
|
|
|
|
|
SpanData spanData = exporter.getExportedSpans().get(0);
|
|
|
|
|
Map<AttributeKey<?>, Object> expectedAttributes = Resource.getDefault()
|
|
|
|
|
.merge(Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, "application")))
|
|
|
|
|
.getAttributes()
|
|
|
|
|
.asMap();
|
|
|
|
|
assertThat(spanData.getResource().getAttributes().asMap()).isEqualTo(expectedAttributes);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void shouldAllowMultipleSpanProcessors() {
|
|
|
|
|
this.contextRunner.withUserConfiguration(CustomConfiguration.class).run((context) -> {
|
|
|
|
@ -297,4 +331,50 @@ class OpenTelemetryAutoConfigurationTests {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Configuration(proxyBeanMethods = false)
|
|
|
|
|
private static class InMemoryRecordingSpanExporterConfiguration {
|
|
|
|
|
|
|
|
|
|
@Bean
|
|
|
|
|
InMemoryRecordingSpanExporter spanExporter() {
|
|
|
|
|
return new InMemoryRecordingSpanExporter();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static class InMemoryRecordingSpanExporter implements SpanExporter {
|
|
|
|
|
|
|
|
|
|
private final List<SpanData> exportedSpans = new ArrayList<>();
|
|
|
|
|
|
|
|
|
|
private final CountDownLatch latch = new CountDownLatch(1);
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public CompletableResultCode export(Collection<SpanData> spans) {
|
|
|
|
|
this.exportedSpans.addAll(spans);
|
|
|
|
|
this.latch.countDown();
|
|
|
|
|
return CompletableResultCode.ofSuccess();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public CompletableResultCode flush() {
|
|
|
|
|
return CompletableResultCode.ofSuccess();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public CompletableResultCode shutdown() {
|
|
|
|
|
this.exportedSpans.clear();
|
|
|
|
|
return CompletableResultCode.ofSuccess();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<SpanData> getExportedSpans() {
|
|
|
|
|
return this.exportedSpans;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void await(Duration timeout) throws InterruptedException, TimeoutException {
|
|
|
|
|
if (!this.latch.await(timeout.toMillis(), TimeUnit.MILLISECONDS)) {
|
|
|
|
|
throw new TimeoutException("Waiting for exporting spans timed out (%s)".formatted(timeout));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|