Skip to content

Commit

Permalink
Move zipkin.Span types in the OpenTelemetry auto-configuration
Browse files Browse the repository at this point in the history
Brave can work without zipkin2 on the classpath, OpenTelemetry can't.
To not force users to have zipkin2 on the classpath, move it into the
OpenTelemetry auto-configuration.

See gh-39049
  • Loading branch information
mhalbritter committed Feb 21, 2024
1 parent 5e844db commit ed4d13a
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,7 @@

package org.springframework.boot.actuate.autoconfigure.tracing.zipkin;

import zipkin2.Span;
import zipkin2.reporter.BytesEncoder;
import zipkin2.reporter.Encoding;
import zipkin2.reporter.SpanBytesEncoder;

import org.springframework.boot.actuate.autoconfigure.tracing.zipkin.ZipkinConfigurations.BraveConfiguration;
import org.springframework.boot.actuate.autoconfigure.tracing.zipkin.ZipkinConfigurations.OpenTelemetryConfiguration;
Expand Down Expand Up @@ -63,10 +60,4 @@ Encoding encoding(ZipkinProperties properties) {
};
}

@Bean
@ConditionalOnMissingBean(value = Span.class, parameterizedContainer = BytesEncoder.class)
BytesEncoder<Span> zipkinSpanEncoder(Encoding encoding) {
return SpanBytesEncoder.forEncoding(encoding);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import zipkin2.reporter.Encoding;
import zipkin2.reporter.HttpEndpointSupplier;
import zipkin2.reporter.HttpEndpointSuppliers;
import zipkin2.reporter.SpanBytesEncoder;
import zipkin2.reporter.brave.AsyncZipkinSpanHandler;
import zipkin2.reporter.brave.MutableSpanBytesEncoder;
import zipkin2.reporter.urlconnection.URLConnectionSender;
Expand Down Expand Up @@ -177,7 +178,7 @@ static class BraveConfiguration {

@Bean
@ConditionalOnMissingBean(value = MutableSpan.class, parameterizedContainer = BytesEncoder.class)
BytesEncoder<MutableSpan> braveSpanEncoder(Encoding encoding,
BytesEncoder<MutableSpan> mutableSpanBytesEncoder(Encoding encoding,
ObjectProvider<Tag<Throwable>> throwableTagProvider) {
Tag<Throwable> throwableTag = throwableTagProvider.getIfAvailable(() -> Tags.ERROR);
return MutableSpanBytesEncoder.create(encoding, throwableTag);
Expand All @@ -188,22 +189,28 @@ BytesEncoder<MutableSpan> braveSpanEncoder(Encoding encoding,
@ConditionalOnBean(BytesMessageSender.class)
@ConditionalOnEnabledTracing
AsyncZipkinSpanHandler asyncZipkinSpanHandler(BytesMessageSender sender,
BytesEncoder<MutableSpan> braveSpanEncoder) {
return AsyncZipkinSpanHandler.newBuilder(sender).build(braveSpanEncoder);
BytesEncoder<MutableSpan> mutableSpanBytesEncoder) {
return AsyncZipkinSpanHandler.newBuilder(sender).build(mutableSpanBytesEncoder);
}

}

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ZipkinSpanExporter.class)
@ConditionalOnClass({ ZipkinSpanExporter.class, Span.class })
static class OpenTelemetryConfiguration {

@Bean
@ConditionalOnMissingBean(value = Span.class, parameterizedContainer = BytesEncoder.class)
BytesEncoder<Span> spanBytesEncoder(Encoding encoding) {
return SpanBytesEncoder.forEncoding(encoding);
}

@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(BytesMessageSender.class)
@ConditionalOnEnabledTracing
ZipkinSpanExporter zipkinSpanExporter(BytesMessageSender sender, BytesEncoder<Span> zipkinSpanEncoder) {
return ZipkinSpanExporter.builder().setSender(sender).setEncoder(zipkinSpanEncoder).build();
ZipkinSpanExporter zipkinSpanExporter(BytesMessageSender sender, BytesEncoder<Span> spanBytesEncoder) {
return ZipkinSpanExporter.builder().setSender(sender).setEncoder(spanBytesEncoder).build();
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ class ZipkinAutoConfigurationTests {
@Test
void shouldSupplyBeans() {
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(Encoding.class)
.hasSingleBean(PropertiesZipkinConnectionDetails.class)
.hasBean("zipkinSpanEncoder"));
.hasSingleBean(PropertiesZipkinConnectionDetails.class));
}

@Test
Expand All @@ -65,14 +64,8 @@ void definesPropertiesBasedConnectionDetailsByDefault() {

@Test
void shouldUseCustomConnectionDetailsWhenDefined() {
this.contextRunner.withBean(ZipkinConnectionDetails.class, () -> new ZipkinConnectionDetails() {

@Override
public String getSpanEndpoint() {
return "http://localhost";
}

})
this.contextRunner
.withBean(ZipkinConnectionDetails.class, () -> new FixedZipkinConnectionDetails("http://localhost"))
.run((context) -> assertThat(context).hasSingleBean(ZipkinConnectionDetails.class)
.doesNotHaveBean(PropertiesZipkinConnectionDetails.class));
}
Expand All @@ -85,6 +78,21 @@ void shouldWorkWithoutSenders() {
.run((context) -> assertThat(context).hasNotFailed());
}

private static final class FixedZipkinConnectionDetails implements ZipkinConnectionDetails {

private final String spanEndpoint;

private FixedZipkinConnectionDetails(String spanEndpoint) {
this.spanEndpoint = spanEndpoint;
}

@Override
public String getSpanEndpoint() {
return this.spanEndpoint;
}

}

@Configuration(proxyBeanMethods = false)
private static final class CustomConfiguration {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import org.springframework.context.annotation.Configuration;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;

/**
* Tests for {@link OpenTelemetryConfiguration}.
Expand All @@ -48,22 +47,40 @@ class ZipkinConfigurationsOpenTelemetryConfigurationTests {

@Test
void shouldSupplyBeans() {
this.contextRunner.withUserConfiguration(SenderConfiguration.class)
.withBean(BytesEncoder.class, () -> mock(BytesEncoder.class))
.run((context) -> assertThat(context).hasSingleBean(ZipkinSpanExporter.class));
this.contextRunner.withUserConfiguration(SenderConfiguration.class, CustomEncoderConfiguration.class)
.run((context) -> {
assertThat(context).hasSingleBean(ZipkinSpanExporter.class);
assertThat(context).hasBean("customSpanEncoder");
});
}

@Test
void shouldNotSupplyZipkinSpanExporterIfSenderIsMissing() {
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ZipkinSpanExporter.class));
this.contextRunner.run((context) -> {
assertThat(context).doesNotHaveBean(ZipkinSpanExporter.class);
assertThat(context).hasBean("spanBytesEncoder");
});
}

@Test
void shouldNotSupplyZipkinSpanExporterIfNotOnClasspath() {
this.contextRunner.withClassLoader(new FilteredClassLoader("io.opentelemetry.exporter.zipkin"))
.withUserConfiguration(SenderConfiguration.class)
.run((context) -> assertThat(context).doesNotHaveBean(ZipkinSpanExporter.class));
.run((context) -> {
assertThat(context).doesNotHaveBean(ZipkinSpanExporter.class);
assertThat(context).doesNotHaveBean("spanBytesEncoder");
});

}

@Test
void shouldBackOffIfZipkinIsNotOnClasspath() {
this.contextRunner.withClassLoader(new FilteredClassLoader("zipkin2.Span"))
.withUserConfiguration(SenderConfiguration.class)
.run((context) -> {
assertThat(context).doesNotHaveBean(ZipkinSpanExporter.class);
assertThat(context).doesNotHaveBean("spanBytesEncoder");
});
}

@Test
Expand All @@ -85,6 +102,7 @@ void shouldUseCustomEncoderBean() {
this.contextRunner.withUserConfiguration(SenderConfiguration.class, CustomEncoderConfiguration.class)
.run((context) -> {
assertThat(context).hasSingleBean(ZipkinSpanExporter.class);
assertThat(context).hasBean("customSpanEncoder");
assertThat(context.getBean(ZipkinSpanExporter.class)).extracting("encoder")
.isInstanceOf(CustomSpanEncoder.class)
.extracting("encoding")
Expand All @@ -99,6 +117,7 @@ void shouldUseCustomEncodingBean() {
CustomEncoderConfiguration.class)
.run((context) -> {
assertThat(context).hasSingleBean(ZipkinSpanExporter.class);
assertThat(context).hasBean("customSpanEncoder");
assertThat(context.getBean(ZipkinSpanExporter.class)).extracting("encoder")
.isInstanceOf(CustomSpanEncoder.class)
.extracting("encoding")
Expand Down Expand Up @@ -140,7 +159,7 @@ ZipkinSpanExporter customZipkinSpanExporter() {
private static final class CustomEncoderConfiguration {

@Bean
BytesEncoder<Span> encoder(Encoding encoding) {
BytesEncoder<Span> customSpanEncoder(Encoding encoding) {
return new CustomSpanEncoder(encoding);
}

Expand Down

0 comments on commit ed4d13a

Please sign in to comment.