TLDR :
TraceAutoConfiguration
from Sleuth@AutoConfigureAfter
the application does not start and fails with message No qualifying bean of type 'zipkin2.reporter.Sender' available
More details :
I'm trying to create a custom Sleuth instrumenting service that can also work when no tracing is available. Here is a really simplified version of the service interface :
public interface SomeService {
String decorate(String value);
}
I then create an AutoConfiguration (as this code is in a separate module, used by many projects) :
@Configuration
@AutoConfigureAfter(name = "org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration")
@Slf4j
public class TestAutoConfiguration {
@ConditionalOnBean(type = "brave.Tracer")
@Configuration
public static class TracedConfiguration {
@Bean
public SomeService someService(Tracer tracer) {
log.info("Create traced SomeService");
return value -> value + " [" + tracer.currentSpan().toString() + "]";
}
}
@ConditionalOnMissingBean(type = "brave.Tracer")
@Configuration
public static class NoTracedConfiguration {
@Bean
public SomeService someService() {
log.info("Create not traced SomeService");
return value -> value + " [not-traced]";
}
}
}
The idea is really to have a kind of Noop version of the service when no Tracer is available.
I then declare the the AutoConfiguration in a spring.factories file as usual.
This is the application I want to run :
@SpringBootApplication
@RestController
@Slf4j
public class ReproApplication {
@Autowired
private SomeService someService;
@GetMapping("/test")
public String test() {
log.info("Test Endpoint called, check TraceId/SpanId/ParentSpanId in log");
return someService.decorate("hello world") + "\n";
}
public static void main(String[] args) {
SpringApplication.run(ReproApplication.class, args);
}
}
For all of this I want to use Zipkin, with a KafkaSpanReporter. So my application.properties look like this :
spring.application.name=repro
server.port=8080
spring.kafka.bootstrapServers=kafka:9092
spring.sleuth.sampler.probability=1.0
spring.zipkin.sender.type=kafka
logging.level.org.springframework.boot.autoconfigure=DEBUG
and my (truncated) pom.xml like this :
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-kafka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
</dependency>
</dependencies>
When I try to run this code I get an error :
No qualifying bean of type 'zipkin2.reporter.Sender' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
If I look at the configuration report I see :
Parameter 2 of method reporter in org.springframework.cloud.sleuth.zipkin2.ZipkinAutoConfiguration required a bean of type 'zipkin2.reporter.Sender' that could not be found.
- Bean method 'kafkaSender' not loaded because @ConditionalOnBean (types: org.springframework.boot.autoconfigure.kafka.KafkaProperties; SearchStrategy: all) did not find any beans of type org.springframework.boot.autoconfigure.kafka.KafkaProperties
This is weird, because there is a @EnableConfigurationProperties(KafkaProperties.class)
on KafkaAutoConfiguration
and the configuration report clearly shows :
KafkaAutoConfiguration matched:
- @ConditionalOnClass found required class 'org.springframework.kafka.core.KafkaTemplate'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
What is even weirder is that if I remove the @AutoConfigureAfter(name = "org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration")
in my AutoConfiguration, the service starts all right => but I get the NoTracedConfiguration
flavour of my bean, so Tracer
is probably not configured yet.
What can I do to fix this problem ?
Finally got it to work removing @AutoConfigureAfter
, @ConditionalOnBean
and @ConditionalOnMissingBean
, using instead @ConditionalOnClass
, @ConditionalOnMissingClass
and reproducing other @Conditionals
from TraceAutoConfiguration
. Not great, but at least working.