Merge branch 'master' into 2.0.x
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
:toc: left
|
||||
:toclevels: 8
|
||||
:nofooter:
|
||||
:sectlinks: true
|
||||
|
||||
Spring Cloud Sleuth
|
||||
====================
|
||||
@@ -768,7 +769,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
|
||||
|
||||
@@ -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:
|
||||
*
|
||||
* <li>
|
||||
* <ul>from the @SpanName annotation if one is present</ul>
|
||||
* <ul>from the @SpanName annotation on the class if one is present</ul>
|
||||
* <ul>from the @SpanName annotation on the method if passed object is of a {@link Method} type</ul>
|
||||
* <ul>from the toString() of the delegate if it's not the
|
||||
* default {@link Object#toString()}</ul>
|
||||
* <ul>the default provided value</ul>
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -55,10 +55,13 @@ import java.lang.annotation.Target;
|
||||
* };
|
||||
* }</pre>
|
||||
*
|
||||
* 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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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() {}
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,7 @@ import org.springframework.data.rest.core.annotation.RepositoryRestResource;
|
||||
import org.springframework.hateoas.PagedResources;
|
||||
import org.springframework.http.RequestEntity;
|
||||
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;
|
||||
|
||||
@@ -58,6 +59,7 @@ import static org.springframework.cloud.sleuth.assertions.SleuthAssertions.then;
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = ReservationServiceApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@DirtiesContext
|
||||
@ActiveProfiles("data")
|
||||
public class SpringDataInstrumentationTests {
|
||||
|
||||
@Autowired
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
spring.autoconfigure.exclude:
|
||||
@@ -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: /**
|
||||
security.ignored: /**
|
||||
|
||||
#disable hibernate by default
|
||||
spring.autoconfigure.exclude: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
|
||||
Reference in New Issue
Block a user