From 253b34b1cf5627c61e8e4cb8e75fcc00d22e5664 Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Mon, 14 Aug 2017 10:10:38 -0400 Subject: [PATCH 1/3] Fixed missing interceptor injection in OAuth2RestTemplate fixes #581 --- spring-cloud-sleuth-core/pom.xml | 5 ++ .../TraceWebClientAutoConfiguration.java | 69 +++++++++++++++++-- .../TraceWebClientAutoConfigurationTests.java | 62 +++++++++++++++++ .../src/test/resources/application.yml | 3 +- 4 files changed, 134 insertions(+), 5 deletions(-) create mode 100644 spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/TraceWebClientAutoConfigurationTests.java diff --git a/spring-cloud-sleuth-core/pom.xml b/spring-cloud-sleuth-core/pom.xml index d06d4433b..88e0c1f65 100644 --- a/spring-cloud-sleuth-core/pom.xml +++ b/spring-cloud-sleuth-core/pom.xml @@ -55,6 +55,11 @@ spring-integration-core true + + org.springframework.security.oauth + spring-security-oauth2 + true + org.springframework spring-context diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceWebClientAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceWebClientAutoConfiguration.java index 8e6b19d49..076fa5015 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceWebClientAutoConfiguration.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceWebClientAutoConfiguration.java @@ -21,11 +21,15 @@ import java.util.Collection; import java.util.List; import javax.annotation.PostConstruct; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.BeanPostProcessor; 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.boot.autoconfigure.security.oauth2.resource.UserInfoRestTemplateCustomizer; import org.springframework.cloud.sleuth.ErrorParser; import org.springframework.cloud.sleuth.Tracer; import org.springframework.cloud.sleuth.instrument.web.HttpSpanInjector; @@ -34,6 +38,7 @@ import org.springframework.cloud.sleuth.instrument.web.TraceWebAutoConfiguration import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.security.oauth2.client.OAuth2RestTemplate; import org.springframework.web.client.RestTemplate; /** @@ -73,12 +78,68 @@ public class TraceWebClientAutoConfiguration { public void init() { if (this.restTemplates != null) { for (RestTemplate restTemplate : this.restTemplates) { - List interceptors = new ArrayList( - restTemplate.getInterceptors()); - interceptors.add(this.traceRestTemplateInterceptor); - restTemplate.setInterceptors(interceptors); + new RestTemplateInterceptorInjector( + this.traceRestTemplateInterceptor).inject(restTemplate); } } } } + + @Configuration + @ConditionalOnClass(UserInfoRestTemplateCustomizer.class) + protected static class TraceOAuthConfiguration { + + @Autowired BeanFactory beanFactory; + + @Bean UserInfoRestTemplateCustomizerBPP userInfoRestTemplateCustomizerBeanPostProcessor() { + return new UserInfoRestTemplateCustomizerBPP(this.beanFactory); + } + + class UserInfoRestTemplateCustomizerBPP implements BeanPostProcessor { + + private final BeanFactory beanFactory; + + UserInfoRestTemplateCustomizerBPP(BeanFactory beanFactory) { + this.beanFactory = beanFactory; + } + + @Override + public Object postProcessBeforeInitialization(Object bean, + String beanName) throws BeansException { + return bean; + } + + @Override + public Object postProcessAfterInitialization(final Object bean, + String beanName) throws BeansException { + final BeanFactory beanFactory = this.beanFactory; + if (bean instanceof UserInfoRestTemplateCustomizer) { + return new UserInfoRestTemplateCustomizer() { + @Override public void customize(OAuth2RestTemplate template) { + final TraceRestTemplateInterceptor interceptor = + beanFactory.getBean(TraceRestTemplateInterceptor.class); + new RestTemplateInterceptorInjector(interceptor).inject(template); + ((UserInfoRestTemplateCustomizer) bean).customize(template); + } + }; + } + return bean; + } + } + } } + +class RestTemplateInterceptorInjector { + private final TraceRestTemplateInterceptor interceptor; + + RestTemplateInterceptorInjector(TraceRestTemplateInterceptor interceptor) { + this.interceptor = interceptor; + } + + void inject(RestTemplate restTemplate) { + List interceptors = new ArrayList( + restTemplate.getInterceptors()); + interceptors.add(this.interceptor); + restTemplate.setInterceptors(interceptors); + } +} \ No newline at end of file diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/TraceWebClientAutoConfigurationTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/TraceWebClientAutoConfigurationTests.java new file mode 100644 index 000000000..40e6702e1 --- /dev/null +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/TraceWebClientAutoConfigurationTests.java @@ -0,0 +1,62 @@ +package org.springframework.cloud.sleuth.instrument.web.client; + +import org.assertj.core.api.BDDAssertions; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoRestTemplateCustomizer; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration; +import org.springframework.cloud.sleuth.instrument.web.TraceHttpAutoConfiguration; +import org.springframework.cloud.sleuth.instrument.web.TraceWebAutoConfiguration; +import org.springframework.cloud.sleuth.log.SleuthLogAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.oauth2.client.OAuth2RestTemplate; +import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.BDDAssertions.then; + +/** + * @author Marcin Grzejszczak + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = TraceWebClientAutoConfigurationTests.Config.class) +public class TraceWebClientAutoConfigurationTests { + + @Autowired Config config; + @Autowired UserInfoRestTemplateCustomizer customizer; + @Autowired TraceRestTemplateInterceptor interceptor; + + @Test + public void should_wrap_UserInfoRestTemplateCustomizer_in_a_trace_representation() { + OAuth2ProtectedResourceDetails details = Mockito.mock(OAuth2ProtectedResourceDetails.class); + OAuth2RestTemplate template = new OAuth2RestTemplate(details); + + this.customizer.customize(template); + + then(this.config.executed).isTrue(); + then(template.getInterceptors()).contains(this.interceptor); + } + + + @Configuration + @ImportAutoConfiguration(classes = { + TraceWebClientAutoConfiguration.class, SleuthLogAutoConfiguration.class, + TraceHttpAutoConfiguration.class, TraceWebAutoConfiguration.class, TraceAutoConfiguration.class }) + static class Config { + + boolean executed = false; + + @Bean UserInfoRestTemplateCustomizer customizer() { + return new UserInfoRestTemplateCustomizer() { + @Override public void customize(OAuth2RestTemplate template) { + Config.this.executed = true; + } + }; + } + } +} \ No newline at end of file diff --git a/spring-cloud-sleuth-core/src/test/resources/application.yml b/spring-cloud-sleuth-core/src/test/resources/application.yml index 5b9e8f669..293cf2e33 100644 --- a/spring-cloud-sleuth-core/src/test/resources/application.yml +++ b/spring-cloud-sleuth-core/src/test/resources/application.yml @@ -14,4 +14,5 @@ ribbon.eureka.enabled: false spring.sleuth.scheduled.skipPattern: "^org.*TestBeanWithScheduledMethodToBeIgnored$" # comma separated list of matchers -spring.sleuth.rxjava.schedulers.ignoredthreads: HystixMetricPoller,^MyCustomThread.*$,^RxComputation.*$ \ No newline at end of file +spring.sleuth.rxjava.schedulers.ignoredthreads: HystixMetricPoller,^MyCustomThread.*$,^RxComputation.*$ +security.ignored: /** \ No newline at end of file From c3d198053f9557a3c0d2df95f3505732040d5237 Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Thu, 17 Aug 2017 13:40:27 +0200 Subject: [PATCH 2/3] Enable spring-data only on demand for tests --- .../src/test/resources/application-data.yml | 1 + spring-cloud-sleuth-core/src/test/resources/application.yml | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 spring-cloud-sleuth-core/src/test/resources/application-data.yml diff --git a/spring-cloud-sleuth-core/src/test/resources/application-data.yml b/spring-cloud-sleuth-core/src/test/resources/application-data.yml new file mode 100644 index 000000000..de733c518 --- /dev/null +++ b/spring-cloud-sleuth-core/src/test/resources/application-data.yml @@ -0,0 +1 @@ +spring.autoconfigure.exclude: \ No newline at end of file diff --git a/spring-cloud-sleuth-core/src/test/resources/application.yml b/spring-cloud-sleuth-core/src/test/resources/application.yml index 293cf2e33..2de958e10 100644 --- a/spring-cloud-sleuth-core/src/test/resources/application.yml +++ b/spring-cloud-sleuth-core/src/test/resources/application.yml @@ -15,4 +15,7 @@ ribbon.eureka.enabled: false spring.sleuth.scheduled.skipPattern: "^org.*TestBeanWithScheduledMethodToBeIgnored$" # comma separated list of matchers spring.sleuth.rxjava.schedulers.ignoredthreads: HystixMetricPoller,^MyCustomThread.*$,^RxComputation.*$ -security.ignored: /** \ No newline at end of file +security.ignored: /** + +#disable hibernate by default +spring.autoconfigure.exclude: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration \ No newline at end of file From f322d7a06c15e794a0795f6a5ba7ab4b09518a61 Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Thu, 17 Aug 2017 14:00:54 +0200 Subject: [PATCH 3/3] @Async Spans should use SpanNamer without this change there's no way to alter the name of the methods annotated with @Async with this change the value passed to @Async annotated method via @SpanName will be the name of the span fixes #653 --- .../main/asciidoc/spring-cloud-sleuth.adoc | 4 +- .../cloud/sleuth/DefaultSpanNamer.java | 19 ++++++-- .../cloud/sleuth/SpanName.java | 5 ++- .../instrument/async/TraceAsyncAspect.java | 12 ++++- .../cloud/sleuth/DefaultSpanNamerTests.java | 24 ++++++++++ .../web/SpringDataInstrumentationTests.java | 2 + .../web/TraceAsyncIntegrationTests.java | 44 +++++++++++++++++++ 7 files changed, 104 insertions(+), 6 deletions(-) diff --git a/docs/src/main/asciidoc/spring-cloud-sleuth.adoc b/docs/src/main/asciidoc/spring-cloud-sleuth.adoc index bbf232e53..cf14a125f 100644 --- a/docs/src/main/asciidoc/spring-cloud-sleuth.adoc +++ b/docs/src/main/asciidoc/spring-cloud-sleuth.adoc @@ -5,6 +5,7 @@ :toc: left :toclevels: 8 :nofooter: +:sectlinks: true Spring Cloud Sleuth ==================== @@ -752,7 +753,8 @@ You can disable this behaviour by setting the value of `spring.sleuth.async.enab If you annotate your method with `@Async` then we'll automatically create a new Span with the following characteristics: - - the Span name will be the annotated method name + - if the method is annotated with `@SpanName` then the value of the annotation will be the Span's name + - if the method is *not* annotated with `@SpanName` the Span name will be the annotated method name - the Span will be tagged with that method's class name and the method name too ==== @Scheduled annotated methods diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/DefaultSpanNamer.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/DefaultSpanNamer.java index 2f077cfa9..c8fd215f3 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/DefaultSpanNamer.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/DefaultSpanNamer.java @@ -16,13 +16,16 @@ package org.springframework.cloud.sleuth; +import java.lang.reflect.Method; + import org.springframework.core.annotation.AnnotationUtils; /** * Default implementation of SpanNamer that tries to get the span name as follows: * *
  • - *
      from the @SpanName annotation if one is present
    + *
      from the @SpanName annotation on the class if one is present
    + *
      from the @SpanName annotation on the method if passed object is of a {@link Method} type
    *
      from the toString() of the delegate if it's not the * default {@link Object#toString()}
    *
      the default provided value
    @@ -37,8 +40,7 @@ public class DefaultSpanNamer implements SpanNamer { @Override public String name(Object object, String defaultValue) { - SpanName annotation = AnnotationUtils - .findAnnotation(object.getClass(), SpanName.class); + SpanName annotation = annotation(object); String spanName = annotation != null ? annotation.value() : object.toString(); // If there is no overridden toString method we'll put a constant value if (isDefaultToString(object, spanName)) { @@ -47,7 +49,18 @@ public class DefaultSpanNamer implements SpanNamer { return spanName; } + private SpanName annotation(Object o) { + if (o instanceof Method) { + return AnnotationUtils.findAnnotation((Method) o, SpanName.class); + } + return AnnotationUtils + .findAnnotation(o.getClass(), SpanName.class); + } + private static boolean isDefaultToString(Object delegate, String spanName) { + if (delegate instanceof Method) { + return delegate.toString().equals(spanName); + } return (delegate.getClass().getName() + "@" + Integer.toHexString(delegate.hashCode())).equals(spanName); } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/SpanName.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/SpanName.java index f676fc0d8..729294111 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/SpanName.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/SpanName.java @@ -55,10 +55,13 @@ import java.lang.annotation.Target; * }; * } * + * Starting with version {@code 1.3.0} you can also put the annotation on an {@link org.springframework.scheduling.annotation.Async} + * annotated method and the value of that annotation will be used as the span name. + * * @author Marcin Grzejszczak * @since 1.0.0 */ -@Target(ElementType.TYPE) +@Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface SpanName { diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceAsyncAspect.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceAsyncAspect.java index 65a82ce86..2d92887f5 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceAsyncAspect.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceAsyncAspect.java @@ -22,6 +22,7 @@ import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.beans.factory.BeanFactory; import org.springframework.cloud.sleuth.Span; +import org.springframework.cloud.sleuth.SpanNamer; import org.springframework.cloud.sleuth.TraceKeys; import org.springframework.cloud.sleuth.Tracer; import org.springframework.cloud.sleuth.util.SpanNameUtil; @@ -46,6 +47,7 @@ public class TraceAsyncAspect { private final Tracer tracer; private final TraceKeys traceKeys; private final BeanFactory beanFactory; + private SpanNamer spanNamer; public TraceAsyncAspect(Tracer tracer, TraceKeys traceKeys, BeanFactory beanFactory) { this.tracer = tracer; @@ -55,8 +57,9 @@ public class TraceAsyncAspect { @Around("execution (@org.springframework.scheduling.annotation.Async * *.*(..))") public Object traceBackgroundThread(final ProceedingJoinPoint pjp) throws Throwable { - Span span = this.tracer.createSpan( + String spanName = spanNamer().name(getMethod(pjp, pjp.getTarget()), SpanNameUtil.toLowerHyphen(pjp.getSignature().getName())); + Span span = this.tracer.createSpan(spanName); this.tracer.addTag(Span.SPAN_LOCAL_COMPONENT_TAG_NAME, ASYNC_COMPONENT); this.tracer.addTag(this.traceKeys.getAsync().getPrefix() + this.traceKeys.getAsync().getClassNameKey(), pjp.getTarget().getClass().getSimpleName()); @@ -76,4 +79,11 @@ public class TraceAsyncAspect { .findMethod(object.getClass(), method.getName(), method.getParameterTypes()); } + SpanNamer spanNamer() { + if (this.spanNamer == null) { + this.spanNamer = this.beanFactory.getBean(SpanNamer.class); + } + return this.spanNamer; + } + } diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/DefaultSpanNamerTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/DefaultSpanNamerTests.java index 18f27dd42..cc865e797 100644 --- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/DefaultSpanNamerTests.java +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/DefaultSpanNamerTests.java @@ -16,7 +16,10 @@ package org.springframework.cloud.sleuth; +import java.lang.reflect.Method; + import org.junit.Test; +import org.springframework.util.ReflectionUtils; import static org.assertj.core.api.BDDAssertions.then; @@ -42,6 +45,18 @@ public class DefaultSpanNamerTests { then(this.defaultSpanNamer.name(new ClassWithoutToString(), "default")).isEqualTo("default"); } + @Test + public void should_return_value_of_span_name_from_annotation_on_method() throws Exception { + Method method = ReflectionUtils.findMethod(ClassWithAnnotatedMethod.class, "method"); + then(this.defaultSpanNamer.name(method, "default")).isEqualTo("foo"); + } + + @Test + public void should_return_default_value_of_span_name_from_annotation_on_method() throws Exception { + Method method = ReflectionUtils.findMethod(ClassWithNonAnnotatedMethod.class, "method"); + then(this.defaultSpanNamer.name(method, "default")).isEqualTo("default"); + } + @SpanName("somevalue") static class ClassWithAnnotation {} @@ -60,4 +75,13 @@ public class DefaultSpanNamerTests { } static class ClassWithoutToString {} + + static class ClassWithAnnotatedMethod { + @SpanName("foo") + void method() {} + } + + static class ClassWithNonAnnotatedMethod { + void method() {} + } } \ No newline at end of file diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/SpringDataInstrumentationTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/SpringDataInstrumentationTests.java index e0ff466d9..65a56dc43 100644 --- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/SpringDataInstrumentationTests.java +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/SpringDataInstrumentationTests.java @@ -51,6 +51,7 @@ import org.springframework.hateoas.Resources; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.web.client.RestTemplate; @@ -62,6 +63,7 @@ import org.awaitility.Awaitility; @RunWith(SpringRunner.class) @SpringBootTest(classes = ReservationServiceApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @DirtiesContext +@ActiveProfiles("data") public class SpringDataInstrumentationTests { @Autowired diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/TraceAsyncIntegrationTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/TraceAsyncIntegrationTests.java index 29645c716..a4928643e 100644 --- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/TraceAsyncIntegrationTests.java +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/TraceAsyncIntegrationTests.java @@ -2,17 +2,21 @@ package org.springframework.cloud.sleuth.instrument.web; import static java.util.concurrent.TimeUnit.SECONDS; +import static org.assertj.core.api.BDDAssertions.then; import static org.springframework.cloud.sleuth.assertions.SleuthAssertions.then; import java.util.concurrent.atomic.AtomicReference; +import org.assertj.core.api.BDDAssertions; import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.sleuth.Sampler; import org.springframework.cloud.sleuth.Span; +import org.springframework.cloud.sleuth.SpanName; import org.springframework.cloud.sleuth.Tracer; import org.springframework.cloud.sleuth.instrument.DefaultTestAutoConfiguration; import org.springframework.cloud.sleuth.sampler.AlwaysSampler; @@ -35,6 +39,11 @@ public class TraceAsyncIntegrationTests { @Autowired Tracer tracer; + @Before + public void cleanup() { + this.classPerformingAsyncLogic.clear(); + } + @Test public void should_set_span_on_an_async_annotated_method() { Span span = givenASpanInCurrentThread(); @@ -42,6 +51,17 @@ public class TraceAsyncIntegrationTests { whenAsyncProcessingTakesPlace(); thenTraceIdIsPassedFromTheCurrentThreadToTheAsyncOne(span); + this.tracer.close(span); + } + + @Test + public void should_set_span_with_custom_method_on_an_async_annotated_method() { + Span span = givenASpanInCurrentThread(); + + whenAsyncProcessingTakesPlaceWithCustomSpanName(); + + thenTraceIdIsPassedFromTheCurrentThreadToTheAsyncOneAndSpanHasCustomName(span); + this.tracer.close(span); } private Span givenASpanInCurrentThread() { @@ -52,6 +72,10 @@ public class TraceAsyncIntegrationTests { this.classPerformingAsyncLogic.invokeAsynchronousLogic(); } + private void whenAsyncProcessingTakesPlaceWithCustomSpanName() { + this.classPerformingAsyncLogic.customNameInvokeAsynchronousLogic(); + } + private void thenTraceIdIsPassedFromTheCurrentThreadToTheAsyncOne(final Span span) { Awaitility.await().atMost(5, SECONDS).untilAsserted( () -> then(TraceAsyncIntegrationTests.this.classPerformingAsyncLogic.getSpan()) @@ -62,6 +86,16 @@ public class TraceAsyncIntegrationTests { .hasATag("method", "invokeAsynchronousLogic")); } + private void thenTraceIdIsPassedFromTheCurrentThreadToTheAsyncOneAndSpanHasCustomName(final Span span) { + Awaitility.await().atMost(5, SECONDS).untilAsserted( + () -> then(TraceAsyncIntegrationTests.this.classPerformingAsyncLogic.getSpan()) + .hasTraceIdEqualTo(span.getTraceId()) + .hasNameEqualTo("foo") + .isALocalComponentSpan() + .hasATag("class", "ClassPerformingAsyncLogic") + .hasATag("method", "customNameInvokeAsynchronousLogic")); + } + @After public void cleanTrace() { TestSpanContextHolder.removeCurrentSpan(); @@ -93,8 +127,18 @@ public class TraceAsyncIntegrationTests { this.span.set(TestSpanContextHolder.getCurrentSpan()); } + @Async + @SpanName("foo") + public void customNameInvokeAsynchronousLogic() { + this.span.set(TestSpanContextHolder.getCurrentSpan()); + } + public Span getSpan() { return this.span.get(); } + + public void clear() { + this.span.set(null); + } } }