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
new file mode 100644
index 000000000..9fdb34f9b
--- /dev/null
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/DefaultSpanNamer.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2013-2016 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.sleuth;
+
+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 toString() of the delegate if it's not the
+ * default {@link Object#toString()}
+ *
the default provided value
+ *
+ *
+ * @see org.springframework.cloud.sleuth.SpanName
+ *
+ * @author Marcin Grzejszczak
+ */
+public class DefaultSpanNamer implements SpanNamer {
+
+ @Override
+ public String name(Object object, String defaultValue) {
+ SpanName annotation = AnnotationUtils
+ .findAnnotation(object.getClass(), SpanName.class);
+ 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)) {
+ return defaultValue;
+ }
+ return spanName;
+ }
+
+ private static boolean isDefaultToString(Object delegate, String 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/Span.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Span.java
index e3b91edd7..fb46f25f4 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Span.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Span.java
@@ -53,6 +53,7 @@ public class Span {
public static final List HEADERS = Arrays.asList(SPAN_ID_NAME, TRACE_ID_NAME,
SPAN_NAME_NAME, PARENT_ID_NAME, PROCESS_ID_NAME, NOT_SAMPLED_NAME);
public static final String SPAN_EXPORT_NAME = "X-Span-Export";
+ public static final String SPAN_LOCAL_COMPONENT_TAG_NAME = "lc";
private final long begin;
private long end = 0;
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
new file mode 100644
index 000000000..a7e2d75f1
--- /dev/null
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/SpanName.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2013-2016 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.sleuth;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ *
+ * Annotation to provide the name for the Span. You should annotate all your
+ * custom {@link java.lang.Runnable} or {@link java.util.concurrent.Callable} classes
+ * for the instrumentation logic to pick up how to name the span.
+ *
+ * If you're using anonymous instances for those classes then you should override the
+ * {@code toString()} method. That way that value will be picked as a span name at
+ * runtime.
+ *
+ * @author Marcin Grzejszczak
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface SpanName {
+ /**
+ * Name of the span to be resolved at runtime
+ */
+ String value();
+}
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/SpanNamer.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/SpanNamer.java
new file mode 100644
index 000000000..3dd2327bb
--- /dev/null
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/SpanNamer.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2013-2016 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.sleuth;
+
+/**
+ * Describes how for a given object a span should be named. In the vast majority
+ * of cases a name should be provided explicitly. In case of instrumentation
+ * where the name has to be resolved at runtime this interface will provide
+ * the name of the span.
+ *
+ * @author Marcin Grzejszczak
+ */
+public interface SpanNamer {
+
+ /**
+ * Retrieves the span name for the given object.
+ *
+ * @param object - object for which span name should be picked
+ * @param defaultValue - the default valued to be returned if span name can't be calculated
+ * @return span name
+ */
+ String name(Object object, String defaultValue);
+}
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/TraceAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/TraceAutoConfiguration.java
index 80625d519..8895f1c06 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/TraceAutoConfiguration.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/TraceAutoConfiguration.java
@@ -25,8 +25,11 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.cloud.sleuth.DefaultSpanNamer;
import org.springframework.cloud.sleuth.Sampler;
+import org.springframework.cloud.sleuth.SpanNamer;
import org.springframework.cloud.sleuth.Tracer;
+import org.springframework.cloud.sleuth.instrument.TraceKeys;
import org.springframework.cloud.sleuth.metric.CounterServiceBasedSpanReporterService;
import org.springframework.cloud.sleuth.metric.NoOpSpanReporterService;
import org.springframework.cloud.sleuth.metric.SleuthMetricProperties;
@@ -60,8 +63,9 @@ public class TraceAutoConfiguration {
@Bean
@ConditionalOnMissingBean(Tracer.class)
public DefaultTracer traceManager(Sampler sampler, Random random,
- ApplicationEventPublisher publisher) {
- return new DefaultTracer(sampler, random, publisher);
+ ApplicationEventPublisher publisher,
+ SpanNamer spanNamer) {
+ return new DefaultTracer(sampler, random, publisher, spanNamer);
}
@Bean
@@ -70,6 +74,18 @@ public class TraceAutoConfiguration {
return new SleuthMetricProperties();
}
+ @Bean
+ @ConditionalOnMissingBean
+ public TraceKeys traceKeys() {
+ return new TraceKeys();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public SpanNamer spanNamer() {
+ return new DefaultSpanNamer();
+ }
+
@Configuration
@ConditionalOnClass(CounterService.class)
@ConditionalOnMissingBean(SpanReporterService.class)
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceKeys.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceKeys.java
index 5616b4f22..dd5ebed39 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceKeys.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceKeys.java
@@ -53,6 +53,10 @@ public class TraceKeys {
private Message message = new Message();
+ private Hystrix hystrix = new Hystrix();
+
+ private Async async = new Async();
+
public Http getHttp() {
return this.http;
}
@@ -61,6 +65,14 @@ public class TraceKeys {
return this.message;
}
+ public Hystrix getHystrix() {
+ return this.hystrix;
+ }
+
+ public Async getAsync() {
+ return this.async;
+ }
+
public void setHttp(Http http) {
this.http = http;
}
@@ -69,6 +81,14 @@ public class TraceKeys {
this.message = message;
}
+ public void setHystrix(Hystrix hystrix) {
+ this.hystrix = hystrix;
+ }
+
+ public void setAsync(Async async) {
+ this.async = async;
+ }
+
public static class Message {
private Payload payload = new Payload();
@@ -283,4 +303,97 @@ public class TraceKeys {
}
}
+ /**
+ * Trace keys related to Hystrix processing
+ */
+ public static class Hystrix {
+
+ /**
+ * Prefix for header names if they are added as tags.
+ */
+ private String prefix = "";
+
+ /**
+ * Name of the command key
+ */
+ private String commandKey = "commandKey";
+
+ public String getPrefix() {
+ return this.prefix;
+ }
+
+ public String getCommandKey() {
+ return this.commandKey;
+ }
+
+ public void setPrefix(String prefix) {
+ this.prefix = prefix;
+ }
+
+ public void setCommandKey(String commandKey) {
+ this.commandKey = commandKey;
+ }
+
+ }
+
+ /**
+ * Trace keys related to async processing
+ */
+ public static class Async {
+
+ /**
+ * Prefix for header names if they are added as tags.
+ */
+ private String prefix = "";
+
+ /**
+ * Name of the thread that executed the async method
+ */
+ private String threadNameKey = "thread";
+
+ /**
+ * Simple name of the class with a method annotated with {@code @Async}
+ * from which the asynchronous process started
+ */
+ private String classNameKey = "class";
+
+ /**
+ * Name of the method annotated with {@code @Async}
+ */
+ private String methodNameKey = "method";
+
+ public String getPrefix() {
+ return this.prefix;
+ }
+
+ public String getThreadNameKey() {
+ return this.threadNameKey;
+ }
+
+ public String getClassNameKey() {
+ return this.classNameKey;
+ }
+
+ public String getMethodNameKey() {
+ return this.methodNameKey;
+ }
+
+ public void setPrefix(String prefix) {
+ this.prefix = prefix;
+ }
+
+ public void setThreadNameKey(String threadNameKey) {
+ this.threadNameKey = threadNameKey;
+ }
+
+ public void setClassNameKey(String classNameKey) {
+ this.classNameKey = classNameKey;
+ }
+
+ public void setMethodNameKey(String methodNameKey) {
+ this.methodNameKey = methodNameKey;
+ }
+
+ }
+
}
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/AsyncDefaultAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/AsyncDefaultAutoConfiguration.java
index 5eb1278e6..1826c8cd7 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/AsyncDefaultAutoConfiguration.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/AsyncDefaultAutoConfiguration.java
@@ -25,6 +25,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.sleuth.Tracer;
+import org.springframework.cloud.sleuth.instrument.TraceKeys;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
@@ -49,8 +50,8 @@ public class AsyncDefaultAutoConfiguration extends AsyncConfigurerSupport {
}
@Bean
- public TraceAsyncAspect traceAsyncAspect(Tracer tracer) {
- return new TraceAsyncAspect(tracer);
+ public TraceAsyncAspect traceAsyncAspect(Tracer tracer, TraceKeys traceKeys) {
+ return new TraceAsyncAspect(tracer, traceKeys);
}
}
\ No newline at end of file
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LazyTraceExecutor.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LazyTraceExecutor.java
index b11cfbc3a..f524c4814 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LazyTraceExecutor.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LazyTraceExecutor.java
@@ -16,11 +16,17 @@
package org.springframework.cloud.sleuth.instrument.async;
+import java.lang.invoke.MethodHandles;
import java.util.concurrent.Executor;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.cloud.sleuth.DefaultSpanNamer;
+import org.springframework.cloud.sleuth.SpanNamer;
import org.springframework.cloud.sleuth.Tracer;
+import org.springframework.cloud.sleuth.instrument.TraceKeys;
/**
* @author Dave Syer
@@ -28,9 +34,13 @@ import org.springframework.cloud.sleuth.Tracer;
*/
public class LazyTraceExecutor implements Executor {
+ private static final Log log = LogFactory.getLog(MethodHandles.lookup().lookupClass());
+
private Tracer tracer;
private final BeanFactory beanFactory;
private final Executor delegate;
+ private TraceKeys traceKeys;
+ private SpanNamer spanNamer;
public LazyTraceExecutor(BeanFactory beanFactory, Executor delegate) {
this.beanFactory = beanFactory;
@@ -45,9 +55,38 @@ public class LazyTraceExecutor implements Executor {
}
catch (NoSuchBeanDefinitionException e) {
this.delegate.execute(command);
+ return;
}
}
- this.delegate.execute(new TraceRunnable(this.tracer, command));
+ this.delegate.execute(new LocalComponentTraceRunnable(this.tracer, traceKeys(), spanNamer(), command));
+ }
+
+ // due to some race conditions trace keys might not be ready yet
+ private TraceKeys traceKeys() {
+ if (this.traceKeys == null) {
+ try {
+ this.traceKeys = this.beanFactory.getBean(TraceKeys.class);
+ }
+ catch (NoSuchBeanDefinitionException e) {
+ log.warn("TraceKeys bean not found - will provide a manually created instance");
+ return new TraceKeys();
+ }
+ }
+ return this.traceKeys;
+ }
+
+ // due to some race conditions trace keys might not be ready yet
+ private SpanNamer spanNamer() {
+ if (this.spanNamer == null) {
+ try {
+ this.spanNamer = this.beanFactory.getBean(SpanNamer.class);
+ }
+ catch (NoSuchBeanDefinitionException e) {
+ log.warn("SpanNamer bean not found - will provide a manually created instance");
+ return new DefaultSpanNamer();
+ }
+ }
+ return this.spanNamer;
}
}
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LocalComponentTraceCallable.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LocalComponentTraceCallable.java
new file mode 100644
index 000000000..a5e9754f0
--- /dev/null
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LocalComponentTraceCallable.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2013-2016 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.sleuth.instrument.async;
+
+import java.util.concurrent.Callable;
+
+import org.springframework.cloud.sleuth.Span;
+import org.springframework.cloud.sleuth.SpanNamer;
+import org.springframework.cloud.sleuth.Tracer;
+import org.springframework.cloud.sleuth.instrument.TraceKeys;
+
+/**
+ *
+ * Callable that starts a span that is a local component span.
+ *
+ * @author Marcin Grzejszczak
+ */
+public class LocalComponentTraceCallable extends TraceCallable {
+
+ protected static final String ASYNC_COMPONENT = "async";
+
+ private final TraceKeys traceKeys;
+
+ public LocalComponentTraceCallable(Tracer tracer, TraceKeys traceKeys,
+ SpanNamer spanNamer, Callable delegate) {
+ super(tracer, spanNamer, delegate);
+ this.traceKeys = traceKeys;
+ }
+
+ public LocalComponentTraceCallable(Tracer tracer, TraceKeys traceKeys,
+ SpanNamer spanNamer, String name, Callable delegate) {
+ super(tracer, spanNamer, delegate, name);
+ this.traceKeys = traceKeys;
+ }
+
+ @Override
+ public V call() throws Exception {
+ Span span = startSpan();
+ try {
+ return this.getDelegate().call();
+ }
+ finally {
+ close(span);
+ }
+ }
+
+ @Override
+ protected Span startSpan() {
+ Span span = getTracer().joinTrace(getSpanName(), getParent());
+ getTracer().addTag(Span.SPAN_LOCAL_COMPONENT_TAG_NAME, ASYNC_COMPONENT);
+ getTracer().addTag(this.traceKeys.getAsync().getPrefix() +
+ this.traceKeys.getAsync().getThreadNameKey(), Thread.currentThread().getName());
+ return span;
+ }
+}
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LocalComponentTraceRunnable.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LocalComponentTraceRunnable.java
new file mode 100644
index 000000000..8439d2eb2
--- /dev/null
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LocalComponentTraceRunnable.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2013-2016 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.sleuth.instrument.async;
+
+import org.springframework.cloud.sleuth.Span;
+import org.springframework.cloud.sleuth.SpanNamer;
+import org.springframework.cloud.sleuth.Tracer;
+import org.springframework.cloud.sleuth.instrument.TraceKeys;
+
+/**
+ *
+ * Runnable that starts a span that is a local component span.
+ *
+ * @author Marcin Grzejszczak
+ */
+public class LocalComponentTraceRunnable extends TraceRunnable {
+
+ protected static final String ASYNC_COMPONENT = "async";
+
+ private final TraceKeys traceKeys;
+
+ public LocalComponentTraceRunnable(Tracer tracer, TraceKeys traceKeys,
+ SpanNamer spanNamer, Runnable delegate) {
+ super(tracer, spanNamer, delegate);
+ this.traceKeys = traceKeys;
+ }
+
+ public LocalComponentTraceRunnable(Tracer tracer, TraceKeys traceKeys,
+ SpanNamer spanNamer, Runnable delegate, String name) {
+ super(tracer, spanNamer, delegate, name);
+ this.traceKeys = traceKeys;
+ }
+
+ @Override
+ public void run() {
+ Span span = startSpan();
+ try {
+ this.getDelegate().run();
+ }
+ finally {
+ close(span);
+ }
+ }
+
+ @Override
+ protected Span startSpan() {
+ Span span = getTracer().joinTrace(getSpanName(), getParent());
+ getTracer().addTag(Span.SPAN_LOCAL_COMPONENT_TAG_NAME, ASYNC_COMPONENT);
+ getTracer().addTag(this.traceKeys.getAsync().getPrefix() +
+ this.traceKeys.getAsync().getThreadNameKey(), Thread.currentThread().getName());
+ return span;
+ }
+}
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 4c2d694e5..3cd7f50dc 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
@@ -21,6 +21,7 @@ import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
+import org.springframework.cloud.sleuth.instrument.TraceKeys;
/**
* Aspect that creates a new Span for running threads executing methods annotated with
@@ -36,15 +37,21 @@ public class TraceAsyncAspect {
private static final String ASYNC_COMPONENT = "async";
private final Tracer tracer;
+ private final TraceKeys traceKeys;
- public TraceAsyncAspect(Tracer tracer) {
+ public TraceAsyncAspect(Tracer tracer, TraceKeys traceKeys) {
this.tracer = tracer;
+ this.traceKeys = traceKeys;
}
@Around("execution (@org.springframework.scheduling.annotation.Async * *.*(..))")
public Object traceBackgroundThread(final ProceedingJoinPoint pjp) throws Throwable {
- String spanName = ASYNC_COMPONENT + ":" + pjp.getTarget().getClass().getSimpleName();
- Span span = this.tracer.startTrace(spanName);
+ Span span = this.tracer.startTrace(pjp.getSignature().getName());
+ 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());
+ this.tracer.addTag(this.traceKeys.getAsync().getPrefix() +
+ this.traceKeys.getAsync().getMethodNameKey(), pjp.getSignature().getName());
try {
return pjp.proceed();
} finally {
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceCallable.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceCallable.java
index 8b1b5968c..d57c26c80 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceCallable.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceCallable.java
@@ -19,19 +19,35 @@ package org.springframework.cloud.sleuth.instrument.async;
import java.util.concurrent.Callable;
import org.springframework.cloud.sleuth.Span;
+import org.springframework.cloud.sleuth.SpanNamer;
import org.springframework.cloud.sleuth.Tracer;
/**
+ * Callable that passes Span between threads. The Span name is
+ * taken either from the passed value or from the {@link SpanNamer}
+ * interface.
+ *
* @author Spencer Gibb
+ * @author Marcin Grzejszczak
*/
-public class TraceCallable extends TraceDelegate> implements Callable {
+public class TraceCallable implements Callable {
- public TraceCallable(Tracer tracer, Callable delegate) {
- super(tracer, delegate);
+ private final Tracer tracer;
+ private final SpanNamer spanNamer;
+ private final Callable delegate;
+ private final String name;
+ private final Span parent;
+
+ public TraceCallable(Tracer tracer, SpanNamer spanNamer, Callable delegate) {
+ this(tracer, spanNamer, delegate, null);
}
- public TraceCallable(Tracer tracer, Callable delegate, String name) {
- super(tracer, delegate, name);
+ public TraceCallable(Tracer tracer, SpanNamer spanNamer, Callable delegate, String name) {
+ this.tracer = tracer;
+ this.spanNamer = spanNamer;
+ this.delegate = delegate;
+ this.name = name;
+ this.parent = tracer.getCurrentSpan();
}
@Override
@@ -45,4 +61,35 @@ public class TraceCallable extends TraceDelegate> implements Call
}
}
+ protected Span startSpan() {
+ return this.tracer.joinTrace(getSpanName(), this.parent);
+ }
+
+ protected String getSpanName() {
+ if (this.name != null) {
+ return this.name;
+ }
+ return this.spanNamer.name(this.delegate, "async");
+ }
+
+ protected void close(Span span) {
+ this.tracer.close(span);
+ }
+
+ public Tracer getTracer() {
+ return this.tracer;
+ }
+
+ public Callable getDelegate() {
+ return this.delegate;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public Span getParent() {
+ return this.parent;
+ }
+
}
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceContinuingCallable.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceContinuingCallable.java
new file mode 100644
index 000000000..fb3a37c5f
--- /dev/null
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceContinuingCallable.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2013-2016 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.sleuth.instrument.async;
+
+import java.util.concurrent.Callable;
+
+import org.springframework.cloud.sleuth.Span;
+import org.springframework.cloud.sleuth.SpanNamer;
+import org.springframework.cloud.sleuth.Tracer;
+
+/**
+ * Trace Callable that continues a span instead of creating a new one
+ *
+ * @author Marcin Grzejszczak
+ */
+public class TraceContinuingCallable extends TraceCallable implements Callable {
+
+ public TraceContinuingCallable(Tracer tracer, SpanNamer spanNamer, Callable delegate) {
+ super(tracer, spanNamer, delegate);
+ }
+
+ @Override
+ protected Span startSpan() {
+ return getTracer().continueSpan(getParent());
+ }
+
+ @Override
+ protected void close(Span span) {
+ getTracer().detach(span);
+ }
+}
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceDelegate.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceDelegate.java
deleted file mode 100644
index f5febe13c..000000000
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceDelegate.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright 2013-2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.sleuth.instrument.async;
-
-import org.springframework.cloud.sleuth.Span;
-import org.springframework.cloud.sleuth.Tracer;
-
-/**
- * @author Spencer Gibb
- */
-public abstract class TraceDelegate {
-
- private static final String ASYNC_COMPONENT = "async";
-
- private final Tracer tracer;
- private final T delegate;
- private final String name;
- private final Span parent;
-
- public TraceDelegate(Tracer tracer, T delegate) {
- this(tracer, delegate, null);
- }
-
- public TraceDelegate(Tracer tracer, T delegate, String name) {
- this.tracer = tracer;
- this.delegate = delegate;
- this.name = name;
- this.parent = tracer.getCurrentSpan();
- }
-
- protected void close(Span span) {
- this.tracer.close(span);
- }
-
- protected Span startSpan() {
- return this.tracer.joinTrace(getSpanName(), this.parent);
- }
-
- protected String getSpanName() {
- return this.name == null ?
- ASYNC_COMPONENT + ":" + Thread.currentThread().getName()
- : this.name;
- }
-
- public Tracer getTracer() {
- return this.tracer;
- }
-
- public T getDelegate() {
- return this.delegate;
- }
-
- public String getName() {
- return this.name;
- }
-
- public Span getParent() {
- return this.parent;
- }
-
- @Override
- public String toString() {
- return "TraceDelegate{" +
- "tracer=" + this.tracer +
- ", delegate=" + this.delegate +
- ", name=" + this.name +
- ", parent=" + this.parent +
- '}';
- }
-}
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceRunnable.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceRunnable.java
index 693a4dd65..d79ce6991 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceRunnable.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceRunnable.java
@@ -17,23 +17,39 @@
package org.springframework.cloud.sleuth.instrument.async;
import org.springframework.cloud.sleuth.Span;
+import org.springframework.cloud.sleuth.SpanNamer;
import org.springframework.cloud.sleuth.Tracer;
/**
+ * Runnable that passes Span between threads. The Span name is
+ * taken either from the passed value or from the {@link SpanNamer}
+ * interface.
+ *
* @author Spencer Gibb
+ * @author Marcin Grzejszczak
*/
-public class TraceRunnable extends TraceDelegate implements Runnable {
+public class TraceRunnable implements Runnable {
- public TraceRunnable(Tracer tracer, Runnable delegate) {
- super(tracer, delegate);
+ private final Tracer tracer;
+ private final SpanNamer spanNamer;
+ private final Runnable delegate;
+ private final String name;
+ private final Span parent;
+
+ public TraceRunnable(Tracer tracer, SpanNamer spanNamer, Runnable delegate) {
+ this(tracer, spanNamer, delegate, null);
}
- public TraceRunnable(Tracer tracer, Runnable delegate, String name) {
- super(tracer, delegate, name);
+ public TraceRunnable(Tracer tracer, SpanNamer spanNamer, Runnable delegate, String name) {
+ this.tracer = tracer;
+ this.spanNamer = spanNamer;
+ this.delegate = delegate;
+ this.name = name;
+ this.parent = tracer.getCurrentSpan();
}
@Override
- public void run() {
+ public void run() {
Span span = startSpan();
try {
this.getDelegate().run();
@@ -42,4 +58,35 @@ public class TraceRunnable extends TraceDelegate implements Runnable {
close(span);
}
}
+
+ protected Span startSpan() {
+ return this.tracer.joinTrace(getSpanName(), this.parent);
+ }
+
+ protected String getSpanName() {
+ if (this.name != null) {
+ return this.name;
+ }
+ return this.spanNamer.name(this.delegate, "async");
+ }
+
+ protected void close(Span span) {
+ this.tracer.close(span);
+ }
+
+ public Tracer getTracer() {
+ return this.tracer;
+ }
+
+ public Runnable getDelegate() {
+ return this.delegate;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public Span getParent() {
+ return this.parent;
+ }
}
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceableExecutorService.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceableExecutorService.java
index 0e2aa0f41..99f885f77 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceableExecutorService.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceableExecutorService.java
@@ -24,7 +24,10 @@ import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import org.springframework.cloud.sleuth.SpanNamer;
import org.springframework.cloud.sleuth.Tracer;
+import org.springframework.cloud.sleuth.instrument.TraceKeys;
+
/**
* A decorator class for {@link ExecutorService} to support tracing in Executors
* @author Gaurav Rai Mazra
@@ -34,20 +37,27 @@ public class TraceableExecutorService implements ExecutorService {
final ExecutorService delegate;
final Tracer tracer;
private final String spanName;
+ final TraceKeys traceKeys;
+ final SpanNamer spanNamer;
- public TraceableExecutorService(final ExecutorService delegate, final Tracer tracer) {
- this(delegate, tracer, null);
+ public TraceableExecutorService(final ExecutorService delegate, final Tracer tracer,
+ TraceKeys traceKeys, SpanNamer spanNamer) {
+ this(delegate, tracer, traceKeys, spanNamer, null);
}
- public TraceableExecutorService(final ExecutorService delegate, final Tracer tracer, String spanName) {
+ public TraceableExecutorService(final ExecutorService delegate, final Tracer tracer,
+ TraceKeys traceKeys, SpanNamer spanNamer, String spanName) {
this.delegate = delegate;
this.tracer = tracer;
this.spanName = spanName;
+ this.traceKeys = traceKeys;
+ this.spanNamer = spanNamer;
}
@Override
public void execute(Runnable command) {
- final Runnable r = new TraceRunnable(this.tracer, command, this.spanName);
+ final Runnable r = new LocalComponentTraceRunnable(this.tracer, this.traceKeys,
+ this.spanNamer, command, this.spanName);
this.delegate.execute(r);
}
@@ -78,19 +88,22 @@ public class TraceableExecutorService implements ExecutorService {
@Override
public Future submit(Callable task) {
- Callable c = new TraceCallable<>(this.tracer, task, this.spanName);
+ Callable c = new LocalComponentTraceCallable<>(this.tracer, this.traceKeys,
+ this.spanNamer, this.spanName, task);
return this.delegate.submit(c);
}
@Override
public Future submit(Runnable task, T result) {
- Runnable r = new TraceRunnable(this.tracer, task, this.spanName);
+ Runnable r = new LocalComponentTraceRunnable(this.tracer, this.traceKeys,
+ this.spanNamer, task, this.spanName);
return this.delegate.submit(r, result);
}
@Override
public Future> submit(Runnable task) {
- Runnable r = new TraceRunnable(this.tracer, task, this.spanName);
+ Runnable r = new LocalComponentTraceRunnable(this.tracer, this.traceKeys,
+ this.spanNamer, task, this.spanName);
return this.delegate.submit(r);
}
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceableScheduledExecutorService.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceableScheduledExecutorService.java
index 5e271ebce..3c6c044e8 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceableScheduledExecutorService.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceableScheduledExecutorService.java
@@ -21,7 +21,9 @@ import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
+import org.springframework.cloud.sleuth.SpanNamer;
import org.springframework.cloud.sleuth.Tracer;
+import org.springframework.cloud.sleuth.instrument.TraceKeys;
/**
* A decorator class for {@link ScheduledExecutorService} to support tracing in Executors
@@ -30,8 +32,9 @@ import org.springframework.cloud.sleuth.Tracer;
*/
public class TraceableScheduledExecutorService extends TraceableExecutorService implements ScheduledExecutorService {
- public TraceableScheduledExecutorService(final ScheduledExecutorService delegate, final Tracer tracer) {
- super(delegate, tracer);
+ public TraceableScheduledExecutorService(final ScheduledExecutorService delegate,
+ final Tracer tracer, TraceKeys traceKeys, SpanNamer spanNamer) {
+ super(delegate, tracer, traceKeys, spanNamer);
}
private ScheduledExecutorService getScheduledExecutorService() {
@@ -40,27 +43,25 @@ public class TraceableScheduledExecutorService extends TraceableExecutorService
@Override
public ScheduledFuture> schedule(Runnable command, long delay, TimeUnit unit) {
- Runnable r = new TraceRunnable(this.tracer, command);
+ Runnable r = new LocalComponentTraceRunnable(this.tracer, this.traceKeys, this.spanNamer, command);
return getScheduledExecutorService().schedule(r, delay, unit);
}
-
-
@Override
public ScheduledFuture schedule(Callable callable, long delay, TimeUnit unit) {
- Callable c = new TraceCallable<>(this.tracer,callable);
+ Callable c = new LocalComponentTraceCallable<>(this.tracer, this.traceKeys, this.spanNamer, callable);
return getScheduledExecutorService().schedule(c, delay, unit);
}
@Override
public ScheduledFuture> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
- Runnable r = new TraceRunnable(this.tracer, command);
+ Runnable r = new LocalComponentTraceRunnable(this.tracer, this.traceKeys, this.spanNamer, command);
return getScheduledExecutorService().scheduleAtFixedRate(r, initialDelay, period, unit);
}
@Override
public ScheduledFuture> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
- Runnable r = new TraceRunnable(this.tracer, command);
+ Runnable r = new LocalComponentTraceRunnable(this.tracer, this.traceKeys, this.spanNamer, command);
return getScheduledExecutorService().scheduleWithFixedDelay(r, initialDelay, delay, unit);
}
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/hystrix/SleuthHystrixAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/hystrix/SleuthHystrixAutoConfiguration.java
index 4017f602f..4b341eccb 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/hystrix/SleuthHystrixAutoConfiguration.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/hystrix/SleuthHystrixAutoConfiguration.java
@@ -3,6 +3,7 @@ package org.springframework.cloud.sleuth.instrument.hystrix;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.sleuth.Tracer;
+import org.springframework.cloud.sleuth.instrument.TraceKeys;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -14,7 +15,7 @@ import com.netflix.hystrix.HystrixCommand;
public class SleuthHystrixAutoConfiguration {
@Bean
- SleuthHystrixConcurrencyStrategy sleuthHystrixConcurrencyStrategy(Tracer tracer) {
- return new SleuthHystrixConcurrencyStrategy(tracer);
+ SleuthHystrixConcurrencyStrategy sleuthHystrixConcurrencyStrategy(Tracer tracer, TraceKeys traceKeys) {
+ return new SleuthHystrixConcurrencyStrategy(tracer, traceKeys);
}
}
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/hystrix/SleuthHystrixConcurrencyStrategy.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/hystrix/SleuthHystrixConcurrencyStrategy.java
index d9ac5b109..8394b3b19 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/hystrix/SleuthHystrixConcurrencyStrategy.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/hystrix/SleuthHystrixConcurrencyStrategy.java
@@ -1,15 +1,14 @@
package org.springframework.cloud.sleuth.instrument.hystrix;
-import java.util.concurrent.Callable;
-
import javax.annotation.PreDestroy;
-
-import org.slf4j.Logger;
-import org.springframework.cloud.sleuth.Span;
-import org.springframework.cloud.sleuth.Tracer;
+import java.util.concurrent.Callable;
import com.netflix.hystrix.strategy.HystrixPlugins;
import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;
+import org.slf4j.Logger;
+import org.springframework.cloud.sleuth.Span;
+import org.springframework.cloud.sleuth.Tracer;
+import org.springframework.cloud.sleuth.instrument.TraceKeys;
public class SleuthHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {
@@ -18,9 +17,11 @@ public class SleuthHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy
.getLogger(SleuthHystrixConcurrencyStrategy.class);
private final Tracer tracer;
+ private final TraceKeys traceKeys;
- public SleuthHystrixConcurrencyStrategy(Tracer tracer) {
+ public SleuthHystrixConcurrencyStrategy(Tracer tracer, TraceKeys traceKeys) {
this.tracer = tracer;
+ this.traceKeys = traceKeys;
try {
HystrixPlugins.getInstance().registerConcurrencyStrategy(this);
}
@@ -41,17 +42,19 @@ public class SleuthHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy
@Override
public Callable wrapCallable(Callable callable) {
- return new HystrixTraceCallable(this.tracer, callable);
+ return new HystrixTraceCallable(this.tracer, this.traceKeys, callable);
}
private static class HystrixTraceCallable implements Callable {
private Tracer tracer;
+ private TraceKeys traceKeys;
private Callable callable;
private Span parent;
- public HystrixTraceCallable(Tracer tracer, Callable callable) {
+ public HystrixTraceCallable(Tracer tracer, TraceKeys traceKeys, Callable callable) {
this.tracer = tracer;
+ this.traceKeys = traceKeys;
this.callable = callable;
this.parent = tracer.getCurrentSpan();
}
@@ -64,8 +67,10 @@ public class SleuthHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy
span = this.tracer.continueSpan(span);
}
else {
- span = this.tracer.startTrace(HYSTRIX_COMPONENT +
- ":" + Thread.currentThread().getName());
+ span = this.tracer.startTrace(HYSTRIX_COMPONENT);
+ this.tracer.addTag(Span.SPAN_LOCAL_COMPONENT_TAG_NAME, HYSTRIX_COMPONENT);
+ this.tracer.addTag(this.traceKeys.getAsync().getPrefix() +
+ this.traceKeys.getAsync().getThreadNameKey(), Thread.currentThread().getName());
created = true;
}
try {
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/hystrix/TraceCommand.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/hystrix/TraceCommand.java
index ee51dee65..6c89f8bc6 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/hystrix/TraceCommand.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/hystrix/TraceCommand.java
@@ -20,6 +20,7 @@ import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
import com.netflix.hystrix.HystrixCommand;
+import org.springframework.cloud.sleuth.instrument.TraceKeys;
/**
* Abstraction over {@code HystrixCommand} that wraps command execution with Trace setting
@@ -36,18 +37,23 @@ public abstract class TraceCommand extends HystrixCommand {
private static final String HYSTRIX_COMPONENT = "hystrix";
private final Tracer tracer;
+ private final TraceKeys traceKeys;
private final Span parentSpan;
- protected TraceCommand(Tracer tracer, Setter setter) {
+ protected TraceCommand(Tracer tracer, TraceKeys traceKeys, Setter setter) {
super(setter);
this.tracer = tracer;
+ this.traceKeys = traceKeys;
this.parentSpan = tracer.getCurrentSpan();
}
@Override
protected R run() throws Exception {
- String spanName = HYSTRIX_COMPONENT + ":" + getCommandKey().name();
- Span span = this.tracer.joinTrace(spanName, this.parentSpan);
+ String commandKeyName = getCommandKey().name();
+ Span span = this.tracer.joinTrace(commandKeyName, this.parentSpan);
+ this.tracer.addTag(Span.SPAN_LOCAL_COMPONENT_TAG_NAME, HYSTRIX_COMPONENT);
+ this.tracer.addTag(this.traceKeys.getHystrix().getPrefix() +
+ this.traceKeys.getHystrix().getCommandKey(), commandKeyName);
try {
return doRun();
}
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceWebAspect.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceWebAspect.java
index e5bd45be4..391183717 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceWebAspect.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceWebAspect.java
@@ -25,8 +25,9 @@ import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.cloud.sleuth.SpanAccessor;
+import org.springframework.cloud.sleuth.SpanNamer;
import org.springframework.cloud.sleuth.Tracer;
-import org.springframework.cloud.sleuth.instrument.async.TraceCallable;
+import org.springframework.cloud.sleuth.instrument.async.TraceContinuingCallable;
import org.springframework.web.context.request.async.WebAsyncTask;
/**
@@ -43,14 +44,19 @@ import org.springframework.web.context.request.async.WebAsyncTask;
*
*
* For controllers an around aspect is created that wraps the {@link Callable#call()}
- * method execution in {@link TraceCallable}
+ * method execution in {@link org.springframework.cloud.sleuth.instrument.async.TraceCallable}
*
*
+ * This aspect will continue a span created by the TraceFilter. It will not create
+ * a new span - since the one in TraceFilter will wait until processing has been
+ * finished
+ *
* @see org.springframework.web.bind.annotation.RestController
* @see org.springframework.stereotype.Controller
* @see org.springframework.web.client.RestOperations
- * @see TraceCallable
+ * @see org.springframework.cloud.sleuth.instrument.async.TraceCallable
* @see Tracer
+ * @see TraceFilter
*
* @author Tomasz Nurkewicz, 4financeIT
* @author Marcin Grzejszczak, 4financeIT
@@ -60,16 +66,17 @@ import org.springframework.web.context.request.async.WebAsyncTask;
@Aspect
public class TraceWebAspect {
- private static final String ASYNC_COMPONENT = "async";
private static final Log log = org.apache.commons.logging.LogFactory
.getLog(TraceWebAspect.class);
private final Tracer tracer;
private final SpanAccessor accessor;
+ private final SpanNamer spanNamer;
- public TraceWebAspect(Tracer tracer, SpanAccessor accessor) {
+ public TraceWebAspect(Tracer tracer, SpanAccessor accessor, SpanNamer spanNamer) {
this.tracer = tracer;
this.accessor = accessor;
+ this.spanNamer = spanNamer;
}
@Pointcut("@within(org.springframework.web.bind.annotation.RestController)")
@@ -103,19 +110,13 @@ public class TraceWebAspect {
if (this.accessor.isTracing()) {
log.debug("Wrapping callable with span ["
+ this.accessor.getCurrentSpan() + "]");
- return new TraceCallable<>(this.tracer, callable);
+ return new TraceContinuingCallable<>(this.tracer, this.spanNamer, callable);
}
else {
return callable;
}
}
- private String spanName(ProceedingJoinPoint pjp) {
- return ASYNC_COMPONENT + ":" +
- pjp.getTarget().getClass().getSimpleName() + "#" +
- "method=" + pjp.getSignature().getName();
- }
-
@Around("anyControllerOrRestControllerWithPublicWebAsyncTaskMethod()")
public Object wrapWebAsyncTaskWithCorrelationId(ProceedingJoinPoint pjp) throws Throwable {
final WebAsyncTask> webAsyncTask = (WebAsyncTask>) pjp.proceed();
@@ -125,8 +126,8 @@ public class TraceWebAspect {
+ this.accessor.getCurrentSpan() + "]");
Field callableField = WebAsyncTask.class.getDeclaredField("callable");
callableField.setAccessible(true);
- callableField.set(webAsyncTask, new TraceCallable<>(this.tracer,
- webAsyncTask.getCallable(), spanName(pjp)));
+ callableField.set(webAsyncTask, new TraceContinuingCallable<>(this.tracer,
+ this.spanNamer, webAsyncTask.getCallable()));
} catch (NoSuchFieldException ex) {
log.warn("Cannot wrap webAsyncTask's callable with TraceCallable", ex);
}
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceWebAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceWebAutoConfiguration.java
index b144bce01..76ddcc029 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceWebAutoConfiguration.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceWebAutoConfiguration.java
@@ -27,6 +27,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.sleuth.SpanAccessor;
+import org.springframework.cloud.sleuth.SpanNamer;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration;
import org.springframework.cloud.sleuth.instrument.TraceKeys;
@@ -67,8 +68,8 @@ public class TraceWebAutoConfiguration {
private TraceKeys traceKeys;
@Bean
- public TraceWebAspect traceWebAspect() {
- return new TraceWebAspect(this.tracer, this.accessor);
+ public TraceWebAspect traceWebAspect(SpanNamer spanNamer) {
+ return new TraceWebAspect(this.tracer, this.accessor, spanNamer);
}
@Bean
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/AbstractTraceHttpRequestInterceptor.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/AbstractTraceHttpRequestInterceptor.java
index c8fdc2092..f22d69d75 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/AbstractTraceHttpRequestInterceptor.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/AbstractTraceHttpRequestInterceptor.java
@@ -53,7 +53,7 @@ abstract class AbstractTraceHttpRequestInterceptor
if (!span.isExportable()) {
setHeader(request, Span.NOT_SAMPLED_NAME, "true");
}
- setHeader(request, Span.SPAN_NAME_NAME, span.getName().toString());
+ setHeader(request, Span.SPAN_NAME_NAME, span.getName());
setIdHeader(request, Span.PARENT_ID_NAME, getParentId(span));
setHeader(request, Span.PROCESS_ID_NAME, span.getProcessId());
}
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/SleuthHystrixInvocationHandler.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/SleuthHystrixInvocationHandler.java
index c4eac4a68..76e38ddb1 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/SleuthHystrixInvocationHandler.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/SleuthHystrixInvocationHandler.java
@@ -15,6 +15,10 @@
*/
package org.springframework.cloud.sleuth.instrument.web.client;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.util.Map;
+
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.HystrixCommandKey;
@@ -22,12 +26,9 @@ import feign.InvocationHandlerFactory;
import feign.InvocationHandlerFactory.MethodHandler;
import feign.Target;
import org.springframework.cloud.sleuth.Tracer;
+import org.springframework.cloud.sleuth.instrument.TraceKeys;
import org.springframework.cloud.sleuth.instrument.hystrix.TraceCommand;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Method;
-import java.util.Map;
-
import static feign.Util.checkNotNull;
/**
@@ -38,12 +39,14 @@ final class SleuthHystrixInvocationHandler implements InvocationHandler {
private final Target> target;
private final Map dispatch;
private final Tracer tracer;
+ private final TraceKeys traceKeys;
SleuthHystrixInvocationHandler(Target> target, Map dispatch,
- Tracer tracer) {
+ Tracer tracer, TraceKeys traceKeys) {
this.tracer = checkNotNull(tracer, "traceManager");
this.target = checkNotNull(target, "target");
this.dispatch = checkNotNull(dispatch, "dispatch");
+ this.traceKeys = checkNotNull(traceKeys, "traceKeys");
}
@Override public Object invoke(final Object proxy, final Method method,
@@ -54,7 +57,7 @@ final class SleuthHystrixInvocationHandler implements InvocationHandler {
.withGroupKey(HystrixCommandGroupKey.Factory.asKey(groupKey))
.andCommandKey(HystrixCommandKey.Factory.asKey(commandKey));
- HystrixCommand