Spring-cloud-sleuth: Regression - Dependency cycle between HttpTracing and actuator endpoint

Created on 7 Jul 2020  ยท  16Comments  ยท  Source: spring-cloud/spring-cloud-sleuth

Describe the bug
Spring Cloud: Hoxton.SR6
Spring Boot: 2.3.1

I've previously reported this issue for an older version in #1420 which is was fixed in 2.1.3 but seems to have come back in 2.2.3 (Hoxton.SR5). This is not reproducible when using 2.2.2 (Hoxton.SR4).

The symptoms are exactly the same as before. When a custom actuator endpoint (i.e. @Endpoint or @RestControllerEndpoint-annotated component) depends (directly or transitively) on HttpTracing, Spring fails to start and reports a dependency cycle.

Sample
sguillope/sleuth-http-tracing-endpoint demonstrates the issue by just starting the app. It's as simple as having this piece of code:

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Endpoint(id = "my-endpoint")
    @Component
    public static class MyEndpoint {
        public MyEndpoint(HttpTracing httpTracing) {
            // do something with httpTracing
        }
    }
}

Here's the startup output:

***************************
APPLICATION FAILED TO START
***************************

Description:

The dependencies of some of the beans in the application context form a cycle:

   tracingFilter defined in class path resource [org/springframework/cloud/sleuth/instrument/web/TraceWebServletAutoConfiguration.class]
โ”Œโ”€โ”€โ”€โ”€โ”€โ”
|  httpTracing defined in class path resource [org/springframework/cloud/sleuth/instrument/web/TraceHttpAutoConfiguration.class]
โ†‘     โ†“
|  sleuthSkipPatternProvider defined in class path resource [org/springframework/cloud/sleuth/instrument/web/TraceWebAutoConfiguration.class]
โ†‘     โ†“
|  application.MyEndpoint defined in file [/Users/sguillope/Projects/sleuth-http-tracing-endpoint/target/classes/com/example/sleuthhttptracingendpoint/Application$MyEndpoint.class]
โ””โ”€โ”€โ”€โ”€โ”€โ”˜

and here's the full exception when enabling debug output:

org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'httpTracing': Requested bean is currently in creation: Is there an unresolvable circular reference?
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.beforeSingletonCreation(DefaultSingletonBeanRegistry.java:347) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:219) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1304) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1224) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:884) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:788) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:227) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1358) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1204) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1109) ~[spring-context-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.lambda$createEndpointBean$1(EndpointDiscoverer.java:145) ~[spring-boot-actuator-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer$EndpointBean.getBean(EndpointDiscoverer.java:469) ~[spring-boot-actuator-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getFilterEndpoint(EndpointDiscoverer.java:329) ~[spring-boot-actuator-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isFilterMatch(EndpointDiscoverer.java:317) ~[spring-boot-actuator-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isEndpointFiltered(EndpointDiscoverer.java:292) ~[spring-boot-actuator-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isEndpointExposed(EndpointDiscoverer.java:265) ~[spring-boot-actuator-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.convertToEndpoints(EndpointDiscoverer.java:181) ~[spring-boot-actuator-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.discoverEndpoints(EndpointDiscoverer.java:125) ~[spring-boot-actuator-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getEndpoints(EndpointDiscoverer.java:117) ~[spring-boot-actuator-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.cloud.sleuth.instrument.web.TraceWebAutoConfiguration$ActuatorSkipPatternProviderConfig.getEndpointsPatterns(TraceWebAutoConfiguration.java:137) ~[spring-cloud-sleuth-core-2.2.3.RELEASE.jar:2.2.3.RELEASE]
    at org.springframework.cloud.sleuth.instrument.web.TraceWebAutoConfiguration$ActuatorSkipPatternProviderConfig.lambda$skipPatternForActuatorEndpointsSamePort$0(TraceWebAutoConfiguration.java:193) ~[spring-cloud-sleuth-core-2.2.3.RELEASE.jar:2.2.3.RELEASE]
    at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195) ~[na:na]
    at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1654) ~[na:na]
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484) ~[na:na]
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) ~[na:na]
    at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913) ~[na:na]
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:na]
    at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578) ~[na:na]
    at org.springframework.cloud.sleuth.instrument.web.TraceWebAutoConfiguration.sleuthSkipPatternProvider(TraceWebAutoConfiguration.java:78) ~[spring-cloud-sleuth-core-2.2.3.RELEASE.jar:2.2.3.RELEASE]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:650) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:483) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1304) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1224) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:884) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:788) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:538) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1304) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1224) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:884) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:788) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:538) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:207) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.boot.web.servlet.ServletContextInitializerBeans.getOrderedBeansOfType(ServletContextInitializerBeans.java:211) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.boot.web.servlet.ServletContextInitializerBeans.addAsRegistrationBean(ServletContextInitializerBeans.java:174) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.boot.web.servlet.ServletContextInitializerBeans.addAsRegistrationBean(ServletContextInitializerBeans.java:169) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.boot.web.servlet.ServletContextInitializerBeans.addAdaptableBeans(ServletContextInitializerBeans.java:154) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.boot.web.servlet.ServletContextInitializerBeans.<init>(ServletContextInitializerBeans.java:86) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.getServletContextInitializerBeans(ServletWebServerApplicationContext.java:255) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.selfInitialize(ServletWebServerApplicationContext.java:229) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.boot.web.embedded.tomcat.TomcatStarter.onStartup(TomcatStarter.java:53) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5128) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1384) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1374) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na]
    at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:140) ~[na:na]
    at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:909) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:841) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1384) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1374) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na]
    at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:140) ~[na:na]
    at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:909) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:262) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.catalina.core.StandardService.startInternal(StandardService.java:421) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:930) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.catalina.startup.Tomcat.start(Tomcat.java:468) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:123) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.<init>(TomcatWebServer.java:104) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getTomcatWebServer(TomcatServletWebServerFactory.java:437) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getWebServer(TomcatServletWebServerFactory.java:191) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:178) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:158) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:545) ~[spring-context-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:143) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:750) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1237) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at com.example.sleuthhttptracingendpoint.Application.main(Application.java:12) ~[classes/:na]
bug

Most helpful comment

Hello, I think that the fix in the commit 39671a76a3850371cba2e15d7b2b6a81a5f307f1 is only a partial one. It only covers when the raised exception is directly BeanCurrentlyInCreationException but there are cases (we are suffering one of them) that the exception is a BeanCreationException that wraps the BeanCurrentlyInCreationException. So the aplicattion is crashing because the exception is not catched in your catch block.
We changed the type of the catched exception to BeanCreationException and both cases are managed.
I think this should be the type of the catched exception or the same case that is arising in our application can arise in any other.
The endpoint causing this in our case is a healthendpoint that tries to create a custom kafka health indicator, but I think it can be reproduced in a variety of situations.
Any thoughts?

All 16 comments

Reverting 3d677d0 in TraceWebAutoConfiguration seems to be fixing the issue.

        @Bean
        @ConditionalOnMissingBean
        SkipPatternProvider sleuthSkipPatternProvider() {
-               return () -> {
-                       StringJoiner joiner = new StringJoiner("|");
-                       for (SingleSkipPattern pattern : this.patterns) {
-                               Optional<Pattern> skipPattern = pattern.skipPattern();
-                               if (skipPattern.isPresent()) {
-                                       Pattern pattern1 = skipPattern.get();
-                                       String s = pattern1.pattern();
-                                       joiner.add(s);
-                               }
-                       }
-                       return Pattern.compile(joiner.toString());
-               };
+               if (this.patterns == null) {
+                       return null;
+               }
+               List<Pattern> presentPatterns = this.patterns.stream()
+                               .map(SingleSkipPattern::skipPattern).filter(Optional::isPresent)
+                               .map(Optional::get).collect(Collectors.toList());
+               if (presentPatterns.isEmpty()) {
+                       return null;
+               }
+               if (presentPatterns.size() == 1) {
+                       Pattern pattern = presentPatterns.get(0);
+                       return () -> pattern;
+               }
+               StringJoiner joiner = new StringJoiner("|");
+               for (Pattern pattern : presentPatterns) {
+                       String s = pattern.pattern();
+                       joiner.add(s);
+               }
+               Pattern pattern = Pattern.compile(joiner.toString());
+               return () -> pattern;
        }

BTW, as a workaround, adding @Lazy on the Endpoint's constructor alleviates the issue

@Endpoint(id = "my-endpoint")
@Component
public static class MyEndpoint {
    @Lazy
    public MyEndpoint(HttpTracing httpTracing) {
        // do something with httpTracing
    }
}

I think the main this is that the field named patterns can create a cycle, so it was a secret reason why access to it was deferred.

I have to ask this question.. why is HttpTracing being injected into user code anyway? Can you say what you are using it for? It is very strange to do this per-endpoint and I'd like to understand what use case this is.

for the record, I think this is bad behavior until proven otherwise. Things we don't test for shouldn't be assumed to work, or intended to work version to version.

However, I was told someone might revert the commit that fixed commonplace problems just to allow this edge case to work. That would be a net loss.

Hence, I grudgingly made this PR :) #1680

Hi @adriancole thanks for your comments. The sample doesn't reflect exactly what we are doing, it was just an easy way to reproduce the issue. Our Endpoint doesn't directly depend on/autowire HttpTracing. But one of our config classes use it to instrument a DynamoDB AWS client using the brave-instrumentation-aws-java-sdk-core library.
Here's a simplified version of what we have:

@Configuration
public class DynamoConfig {
    @Bean
    public AmazonDynamoDB dynamoDb(HttpTracing httpTracing) {
        // ... more code here
        final AmazonDynamoDBClientBuilder clientBuilder = AmazonDynamoDBClientBuilder.standard()
                .withCredentials(credentials)
                .withEndpointConfiguration(endpointConfiguration);
        return AwsClientTracing.create(httpTracing).build(clientBuilder);
    }
}

```java
@Service
public class MyService {
@Autowired
private AmazonDynamoDB dynamoDb;

public void create() {
    // ... some code here
}

}

```java
@RestControllerEndpoint(id = "my-endpoint")
public class MyRestEndpoint {
    @Autowired
    private MyService myService;

   // ... call myService.create() in handler method here
}

Are we doing something wrong?

What you are doing makes sense in this context, and I'm learning through this that actuator was used for complex controllers. Curious what are these controllers doing? Ex why are they actuator as opposed to normal rest endpoints? (this is to teach me, not criticize)

I changed the description of #1680. thanks for the feedback!

What you are doing makes sense in this context, and I'm learning through this that actuator was used for complex controllers. Curious what are these controllers doing? Ex why are they actuator as opposed to normal rest endpoints? (this is to teach me, not criticize)

@adriancole Just realised I never came back to you on this :|
We have an admin endpoint which is used to trigger the reprocessing of SQS messages that were DLQ'ed. (hence why we have a dependency on zipkin-instrumented aws-sdk beans)
This admin endpoint is declared as @RestControllerEndpoint. Fundamentally yes it could simply be a normal rest controller, however I think conceptually it creates a nice separation from our normal API and also I believe we have specific security setup in place to secure these admin endpoints in a standard way.

Hello, I think that the fix in the commit 39671a76a3850371cba2e15d7b2b6a81a5f307f1 is only a partial one. It only covers when the raised exception is directly BeanCurrentlyInCreationException but there are cases (we are suffering one of them) that the exception is a BeanCreationException that wraps the BeanCurrentlyInCreationException. So the aplicattion is crashing because the exception is not catched in your catch block.
We changed the type of the catched exception to BeanCreationException and both cases are managed.
I think this should be the type of the catched exception or the same case that is arising in our application can arise in any other.
The endpoint causing this in our case is a healthendpoint that tries to create a custom kafka health indicator, but I think it can be reproduced in a variety of situations.
Any thoughts?

Sure, let's reopen this one and if you're willing to file a PR against 2.2.x branch, that would be asweomse!

Sure @marcingrzejszczak I'll file a PR

We found that in our project we can remove the cyclic reference by means of removing an early 'getBeansOfType' invocation. So with this change in our project we are not currently suffering of this cyclic reference anymore.

But we think some otherproject could need to get a bean the way we did and provoke a BeanCurrentlyIncreationException wrapped by a BeanCreationException as it was the case with us.
We find interesting to broaden the type of the catch to BeanCreationException and this is the reason of the slight change proposed in #1722
Feel free to accep or discard if you consider the change is not correct.

Because _BeanCreationException_ is too generic, it is dangerous to catch it and continue. I think it would be better always trace the exception (DEBUG could be an adequate level), and only proceed if the exception is a wrapper for _BeanCurrentlyInCreationException_ or directly a _BeanCurrentlyInCreationException_., throwing exception in other case.

@oburgosm that makes sense, good idea. Anyone willing to make a PR?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

oburgosm picture oburgosm  ยท  4Comments

apolischuk picture apolischuk  ยท  7Comments

davidmelia picture davidmelia  ยท  4Comments

longting picture longting  ยท  7Comments

gerasimovv88 picture gerasimovv88  ยท  7Comments