[#168] Introduced local components for async

Added changes following review
    * added comments
    * added javadocs
    * added naming basing on @SpanName and toString()
    * added default 'async' naming if there is no overriden span name
    * removed TraceDelegate after review
    * introduced SpanNamer

fixes #168
This commit is contained in:
Marcin Grzejszczak
2016-02-17 17:10:54 +01:00
parent beb4aa0a5b
commit cf6f629663
40 changed files with 991 additions and 221 deletions

View File

@@ -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:
*
* <li>
* <ul>from the @SpanName annotation if one is present</ul>
* <ul>from the toString() of the delegate if it's not the
* default {@link Object#toString()}</ul>
* <ul>the default provided value</ul>
* </li>
*
* @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);
}
}

View File

@@ -53,6 +53,7 @@ public class Span {
public static final List<String> 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;

View File

@@ -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();
}

View File

@@ -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);
}

View File

@@ -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)

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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<V> extends TraceCallable<V> {
protected static final String ASYNC_COMPONENT = "async";
private final TraceKeys traceKeys;
public LocalComponentTraceCallable(Tracer tracer, TraceKeys traceKeys,
SpanNamer spanNamer, Callable<V> delegate) {
super(tracer, spanNamer, delegate);
this.traceKeys = traceKeys;
}
public LocalComponentTraceCallable(Tracer tracer, TraceKeys traceKeys,
SpanNamer spanNamer, String name, Callable<V> 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;
}
}

View File

@@ -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;
}
}

View File

@@ -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 {

View File

@@ -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<V> extends TraceDelegate<Callable<V>> implements Callable<V> {
public class TraceCallable<V> implements Callable<V> {
public TraceCallable(Tracer tracer, Callable<V> delegate) {
super(tracer, delegate);
private final Tracer tracer;
private final SpanNamer spanNamer;
private final Callable<V> delegate;
private final String name;
private final Span parent;
public TraceCallable(Tracer tracer, SpanNamer spanNamer, Callable<V> delegate) {
this(tracer, spanNamer, delegate, null);
}
public TraceCallable(Tracer tracer, Callable<V> delegate, String name) {
super(tracer, delegate, name);
public TraceCallable(Tracer tracer, SpanNamer spanNamer, Callable<V> 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<V> extends TraceDelegate<Callable<V>> 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<V> getDelegate() {
return this.delegate;
}
public String getName() {
return this.name;
}
public Span getParent() {
return this.parent;
}
}

View File

@@ -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<V> extends TraceCallable<V> implements Callable<V> {
public TraceContinuingCallable(Tracer tracer, SpanNamer spanNamer, Callable<V> delegate) {
super(tracer, spanNamer, delegate);
}
@Override
protected Span startSpan() {
return getTracer().continueSpan(getParent());
}
@Override
protected void close(Span span) {
getTracer().detach(span);
}
}

View File

@@ -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<T> {
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 +
'}';
}
}

View File

@@ -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<Runnable> 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<Runnable> 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;
}
}

View File

@@ -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 <T> Future<T> submit(Callable<T> task) {
Callable<T> c = new TraceCallable<>(this.tracer, task, this.spanName);
Callable<T> c = new LocalComponentTraceCallable<>(this.tracer, this.traceKeys,
this.spanNamer, this.spanName, task);
return this.delegate.submit(c);
}
@Override
public <T> Future<T> 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);
}

View File

@@ -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 <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
Callable<V> c = new TraceCallable<>(this.tracer,callable);
Callable<V> 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);
}

View File

@@ -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);
}
}

View File

@@ -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 <T> Callable<T> wrapCallable(Callable<T> callable) {
return new HystrixTraceCallable<T>(this.tracer, callable);
return new HystrixTraceCallable<T>(this.tracer, this.traceKeys, callable);
}
private static class HystrixTraceCallable<S> implements Callable<S> {
private Tracer tracer;
private TraceKeys traceKeys;
private Callable<S> callable;
private Span parent;
public HystrixTraceCallable(Tracer tracer, Callable<S> callable) {
public HystrixTraceCallable(Tracer tracer, TraceKeys traceKeys, Callable<S> 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 {

View File

@@ -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<R> extends HystrixCommand<R> {
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();
}

View File

@@ -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;
* </ul>
* <p/>
* 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}
* <p/>
*
* 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);
}

View File

@@ -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

View File

@@ -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());
}

View File

@@ -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<Method, MethodHandler> dispatch;
private final Tracer tracer;
private final TraceKeys traceKeys;
SleuthHystrixInvocationHandler(Target<?> target, Map<Method, MethodHandler> 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<Object> hystrixCommand = new TraceCommand<Object>(this.tracer,
HystrixCommand<Object> hystrixCommand = new TraceCommand<Object>(this.tracer, this.traceKeys,
setter) {
@Override public Object doRun() throws Exception {
try {
@@ -79,15 +82,18 @@ final class SleuthHystrixInvocationHandler implements InvocationHandler {
static final class Factory implements InvocationHandlerFactory {
private final Tracer tracer;
private final TraceKeys traceKeys;
public Factory(Tracer tracer) {
public Factory(Tracer tracer, TraceKeys traceKeys) {
this.tracer = tracer;
this.traceKeys = traceKeys;
}
@Override public InvocationHandler create(
@SuppressWarnings("rawtypes") Target target,
Map<Method, MethodHandler> dispatch) {
return new SleuthHystrixInvocationHandler(target, dispatch, this.tracer);
return new SleuthHystrixInvocationHandler(target, dispatch, this.tracer,
this.traceKeys);
}
}
}

View File

@@ -40,6 +40,7 @@ import org.springframework.cloud.sleuth.SpanAccessor;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.event.ClientReceivedEvent;
import org.springframework.cloud.sleuth.event.ClientSentEvent;
import org.springframework.cloud.sleuth.instrument.TraceKeys;
import org.springframework.cloud.sleuth.instrument.hystrix.SleuthHystrixAutoConfiguration;
import org.springframework.cloud.sleuth.instrument.hystrix.SleuthHystrixConcurrencyStrategy;
import org.springframework.context.ApplicationEvent;
@@ -88,9 +89,9 @@ public class TraceFeignClientAutoConfiguration {
@ConditionalOnClass(HystrixCommand.class)
@ConditionalOnMissingBean(SleuthHystrixConcurrencyStrategy.class)
@ConditionalOnProperty(name = "feign.hystrix.enabled", matchIfMissing = true)
public Feign.Builder feignHystrixBuilder(Tracer tracer) {
public Feign.Builder feignHystrixBuilder(Tracer tracer, TraceKeys traceKeys) {
return HystrixFeign.builder().invocationHandlerFactory(
new SleuthHystrixInvocationHandler.Factory(tracer));
new SleuthHystrixInvocationHandler.Factory(tracer, traceKeys));
}
@Bean

View File

@@ -21,6 +21,7 @@ import java.util.concurrent.Callable;
import org.springframework.cloud.sleuth.Sampler;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanNamer;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.event.SpanAcquiredEvent;
import org.springframework.cloud.sleuth.event.SpanContinuedEvent;
@@ -41,11 +42,14 @@ public class DefaultTracer implements Tracer {
private final Random random;
private final SpanNamer spanNamer;
public DefaultTracer(Sampler defaultSampler, Random random,
ApplicationEventPublisher publisher) {
ApplicationEventPublisher publisher, SpanNamer spanNamer) {
this.defaultSampler = defaultSampler;
this.random = random;
this.publisher = publisher;
this.spanNamer = spanNamer;
}
@Override
@@ -198,7 +202,7 @@ public class DefaultTracer implements Tracer {
@Override
public <V> Callable<V> wrap(Callable<V> callable) {
if (isTracing()) {
return new TraceCallable<>(this, callable);
return new TraceCallable<>(this, this.spanNamer, callable);
}
return callable;
}
@@ -211,7 +215,7 @@ public class DefaultTracer implements Tracer {
@Override
public Runnable wrap(Runnable runnable) {
if (isTracing()) {
return new TraceRunnable(this, runnable);
return new TraceRunnable(this, this.spanNamer, runnable);
}
return runnable;
}

View File

@@ -0,0 +1,63 @@
/*
* 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.junit.Test;
import static org.assertj.core.api.BDDAssertions.then;
/**
* @author Marcin Grzejszczak
*/
public class DefaultSpanNamerTest {
DefaultSpanNamer defaultSpanNamer = new DefaultSpanNamer();
@Test
public void should_return_value_of_span_name_from_annotation() throws Exception {
then(this.defaultSpanNamer.name(new ClassWithAnnotation(), "default")).isEqualTo("somevalue");
}
@Test
public void should_return_value_of_span_name_from_to_string_if_annotation_is_missing() throws Exception {
then(this.defaultSpanNamer.name(fromAnonymousClassWithCustomToString(), "default")).isEqualTo("some-other-value");
}
@Test
public void should_return_default_value_if_tostring_wasnt_overridden() throws Exception {
then(this.defaultSpanNamer.name(new ClassWithoutToString(), "default")).isEqualTo("default");
}
@SpanName("somevalue")
static class ClassWithAnnotation {}
private Runnable fromAnonymousClassWithCustomToString() {
return new Runnable() {
@Override
public void run() {
}
@Override
public String toString() {
return "some-other-value";
}
};
}
static class ClassWithoutToString {}
}

View File

@@ -54,6 +54,16 @@ public class SpanAssert extends AbstractAssert<SpanAssert, Span> {
return this;
}
public SpanAssert nameStartsWith(String string) {
isNotNull();
if (!this.actual.getName().startsWith(string)) {
String message = String.format("Expected span's name to start with <%s> but it was equal to <%s>", string, this.actual.getName());
log.error(message);
failWithMessage(message);
}
return this;
}
public SpanAssert hasNameNotEqualTo(String name) {
isNotNull();
if (Objects.equals(this.actual.getName(), name)) {
@@ -63,4 +73,33 @@ public class SpanAssert extends AbstractAssert<SpanAssert, Span> {
}
return this;
}
public SpanAssert isALocalComponentSpan() {
isNotNull();
if (!this.actual.tags().containsKey(Span.SPAN_LOCAL_COMPONENT_TAG_NAME)) {
String message = String.format("Expected span to be a local component. "
+ "LC tag is missing. Found tags are <%s>", this.actual.tags());
log.error(message);
failWithMessage(message);
}
return this;
}
public SpanAssert hasATag(String tagKey, String tagValue) {
isNotNull();
if (!this.actual.tags().containsKey(tagKey)) {
String message = String.format("Expected span to have the tag with key <%s>. "
+ "Found tags are <%s>", tagKey, this.actual.tags());
log.error(message);
failWithMessage(message);
}
String foundTagValue = this.actual.tags().get(tagKey);
if (!foundTagValue.equals(tagValue)) {
String message = String.format("Expected span to have the tag with key <%s> and value <%s>. "
+ "Found value for that tag is <%s>", tagKey, tagValue, foundTagValue);
log.error(message);
failWithMessage(message);
}
return this;
}
}

View File

@@ -10,22 +10,23 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.cloud.sleuth.DefaultSpanNamer;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.instrument.async.TraceCallable;
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
import org.springframework.cloud.sleuth.trace.DefaultTracer;
import org.springframework.cloud.sleuth.trace.TestSpanContextHolder;
import org.springframework.context.ApplicationEventPublisher;
import static org.assertj.core.api.BDDAssertions.then;
import static org.springframework.cloud.sleuth.assertions.SleuthAssertions.then;
@RunWith(MockitoJUnitRunner.class)
public class TraceCallableTests {
ExecutorService executor = Executors.newSingleThreadExecutor();
Tracer tracer = new DefaultTracer(new AlwaysSampler(),
new Random(), Mockito.mock(ApplicationEventPublisher.class));
new Random(), Mockito.mock(ApplicationEventPublisher.class), new DefaultSpanNamer());
@After
public void clean() {
@@ -71,6 +72,23 @@ public class TraceCallableTests {
then(secondSpan).isNull();
}
@Test
public void should_take_name_of_span_from_span_name_annotation()
throws Exception {
Span span = whenATraceKeepingCallableGetsSubmitted();
then(span).hasNameEqualTo("some-callable-name-from-annotation");
}
@Test
public void should_take_name_of_span_from_to_string_if_span_name_annotation_is_missing()
throws Exception {
Span span = whenCallableGetsSubmitted(
thatRetrievesTraceFromThreadLocal());
then(span).hasNameEqualTo("some-callable-name-from-to-string");
}
private Span givenSpanIsAlreadyActive() {
return this.tracer.startTrace("http:parent");
}
@@ -81,6 +99,11 @@ public class TraceCallableTests {
public Span call() throws Exception {
return TestSpanContextHolder.getCurrentSpan();
}
@Override
public String toString() {
return "some-callable-name-from-to-string";
}
};
}
@@ -91,13 +114,29 @@ public class TraceCallableTests {
private Span whenCallableGetsSubmitted(Callable<Span> callable)
throws InterruptedException, java.util.concurrent.ExecutionException {
return this.executor.submit(new TraceCallable<>(this.tracer, callable))
return this.executor.submit(new TraceCallable<>(this.tracer, new DefaultSpanNamer(), callable))
.get();
}
private Span whenATraceKeepingCallableGetsSubmitted()
throws InterruptedException, java.util.concurrent.ExecutionException {
return this.executor.submit(new TraceCallable<>(this.tracer, new DefaultSpanNamer(),
new TraceKeepingCallable())).get();
}
private Span whenNonTraceableCallableGetsSubmitted(Callable<Span> callable)
throws InterruptedException, java.util.concurrent.ExecutionException {
return this.executor.submit(callable).get();
}
@SpanName("some-callable-name-from-annotation")
static class TraceKeepingCallable implements Callable<Span> {
public Span span;
@Override
public Span call() throws Exception {
this.span = TestSpanContextHolder.getCurrentSpan();
return this.span;
}
}
}

View File

@@ -1,22 +1,24 @@
package org.springframework.cloud.sleuth.instrument.async;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.cloud.sleuth.DefaultSpanNamer;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.instrument.async.TraceRunnable;
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
import org.springframework.cloud.sleuth.trace.DefaultTracer;
import org.springframework.cloud.sleuth.trace.TestSpanContextHolder;
import org.springframework.context.ApplicationEventPublisher;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import static org.springframework.cloud.sleuth.assertions.SleuthAssertions.then;
@RunWith(MockitoJUnitRunner.class)
@@ -24,7 +26,7 @@ public class TraceRunnableTests {
ExecutorService executor = Executors.newSingleThreadExecutor();
Tracer tracer = new DefaultTracer(new AlwaysSampler(),
new Random(), Mockito.mock(ApplicationEventPublisher.class));
new Random(), Mockito.mock(ApplicationEventPublisher.class), new DefaultSpanNamer());
@After
public void cleanup() {
@@ -70,6 +72,27 @@ public class TraceRunnableTests {
then(secondSpan).as("unexpected span").isNull();
}
@Test
public void should_take_name_of_span_from_span_name_annotation()
throws Exception {
TraceKeepingRunnable traceKeepingRunnable = runnableThatRetrievesTraceFromThreadLocal();
whenRunnableGetsSubmitted(traceKeepingRunnable);
then(traceKeepingRunnable.span).hasNameEqualTo("some-runnable-name-from-annotation");
}
@Test
public void should_take_name_of_span_from_to_string_if_span_name_annotation_is_missing()
throws Exception {
final AtomicReference<Span> span = new AtomicReference<>();
Runnable runnable = runnableWithCustomToString(span);
whenRunnableGetsSubmitted(runnable);
then(span.get()).hasNameEqualTo("some-runnable-name-from-to-string");
}
private TraceKeepingRunnable runnableThatRetrievesTraceFromThreadLocal() {
return new TraceKeepingRunnable();
}
@@ -78,8 +101,8 @@ public class TraceRunnableTests {
whenRunnableGetsSubmitted(runnable);
}
private void whenRunnableGetsSubmitted(Runnable callable) throws Exception {
this.executor.submit(new TraceRunnable(this.tracer, callable)).get();
private void whenRunnableGetsSubmitted(Runnable runnable) throws Exception {
this.executor.submit(new TraceRunnable(this.tracer, new DefaultSpanNamer(), runnable)).get();
}
private void whenNonTraceableRunnableGetsSubmitted(Runnable callable)
@@ -87,6 +110,20 @@ public class TraceRunnableTests {
this.executor.submit(callable).get();
}
private Runnable runnableWithCustomToString(final AtomicReference<Span> span) {
return new Runnable() {
@Override
public void run() {
span.set(TestSpanContextHolder.getCurrentSpan());
}
@Override public String toString() {
return "some-runnable-name-from-to-string";
}
};
}
@SpanName("some-runnable-name-from-annotation")
static class TraceKeepingRunnable implements Runnable {
public Span span;

View File

@@ -16,7 +16,9 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
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;
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
import org.springframework.cloud.sleuth.trace.DefaultTracer;
import org.springframework.cloud.sleuth.trace.TestSpanContextHolder;
@@ -30,6 +32,7 @@ public class TraceableExecutorServiceTests {
private static int TOTAL_THREADS = 10;
@Mock ApplicationEventPublisher publisher;
@Mock SpanNamer spanNamer;
Tracer tracer;
ExecutorService executorService = Executors.newFixedThreadPool(3);
ExecutorService traceManagerableExecutorService;
@@ -37,8 +40,10 @@ public class TraceableExecutorServiceTests {
@Before
public void setup() {
this.tracer = new DefaultTracer(new AlwaysSampler(), new Random(), this.publisher);
this.traceManagerableExecutorService = new TraceableExecutorService(this.executorService, this.tracer);
this.tracer = new DefaultTracer(new AlwaysSampler(), new Random(), this.publisher,
spanNamer);
this.traceManagerableExecutorService = new TraceableExecutorService(this.executorService,
this.tracer, new TraceKeys(), this.spanNamer);
TestSpanContextHolder.removeCurrentSpan();
}

View File

@@ -6,15 +6,18 @@ import com.jayway.awaitility.Awaitility;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.strategy.HystrixPlugins;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.sleuth.Sampler;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.instrument.DefaultTestAutoConfiguration;
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
import org.springframework.cloud.sleuth.trace.TestSpanContextHolder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -36,6 +39,7 @@ public class HystrixAnnotationsIntegrationTests {
Tracer tracer;
@BeforeClass
@AfterClass
public static void reset() {
HystrixPlugins.reset();
}
@@ -43,29 +47,33 @@ public class HystrixAnnotationsIntegrationTests {
@After
public void cleanTrace() {
TestSpanContextHolder.removeCurrentSpan();
HystrixPlugins.reset();
}
@Test
public void should_set_span_on_an_hystrix_command_annotated_method() {
public void should_continue_current_span_when_executed_a_hystrix_command_annotated_method() {
Span span = givenASpanInCurrentThread();
whenHystrixCommandAnnotatedMethodGetsExecuted();
thenTraceIdIsPassedFromTheCurrentThreadToTheHystrixOne(span);
thenSpanInHystrixThreadIsContinued(span);
}
@Test
public void should_create_new_span_with_thread_name_when_executed_a_hystrix_command_annotated_method() {
whenHystrixCommandAnnotatedMethodGetsExecuted();
thenSpanInHystrixThreadIsCreated();
}
private Span givenASpanInCurrentThread() {
Span span = this.tracer.startTrace("http:existing");
this.tracer.continueSpan(span);
return span;
return this.tracer.startTrace("http:existing");
}
private void whenHystrixCommandAnnotatedMethodGetsExecuted() {
this.catcher.invokeLogicWrappedInHystrixCommand();
}
private void thenTraceIdIsPassedFromTheCurrentThreadToTheHystrixOne(final Span span) {
private void thenSpanInHystrixThreadIsContinued(final Span span) {
then(span).isNotNull();
Awaitility.await().until(new Runnable() {
@Override
@@ -80,6 +88,17 @@ public class HystrixAnnotationsIntegrationTests {
});
}
private void thenSpanInHystrixThreadIsCreated() {
Awaitility.await().until(new Runnable() {
@Override
public void run() {
then(HystrixAnnotationsIntegrationTests.this.catcher.getSpan())
.nameStartsWith("hystrix")
.isALocalComponentSpan();
}
});
}
@DefaultTestAutoConfiguration
@EnableHystrix
@Configuration
@@ -90,6 +109,11 @@ public class HystrixAnnotationsIntegrationTests {
return new HystrixCommandInvocationSpanCatcher();
}
@Bean
Sampler sampler() {
return new AlwaysSampler();
}
}
static class HystrixCommandInvocationSpanCatcher {
@@ -119,5 +143,9 @@ public class HystrixAnnotationsIntegrationTests {
}
return this.spanCaughtFromHystrixThread.get().getName();
}
public Span getSpan() {
return this.spanCaughtFromHystrixThread.get();
}
}
}

View File

@@ -2,6 +2,7 @@ package org.springframework.cloud.sleuth.instrument.hystrix;
import java.util.Random;
import com.netflix.hystrix.HystrixCommandKey;
import com.netflix.hystrix.HystrixCommandProperties;
import com.netflix.hystrix.HystrixThreadPoolProperties;
import com.netflix.hystrix.strategy.HystrixPlugins;
@@ -9,8 +10,10 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.cloud.sleuth.DefaultSpanNamer;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.instrument.TraceKeys;
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
import org.springframework.cloud.sleuth.trace.DefaultTracer;
import org.springframework.cloud.sleuth.trace.TestSpanContextHolder;
@@ -18,13 +21,13 @@ import org.springframework.context.ApplicationEventPublisher;
import static com.netflix.hystrix.HystrixCommand.Setter.withGroupKey;
import static com.netflix.hystrix.HystrixCommandGroupKey.Factory.asKey;
import static org.assertj.core.api.BDDAssertions.then;
import static org.springframework.cloud.sleuth.assertions.SleuthAssertions.then;
public class TraceCommandTests {
static final long EXPECTED_TRACE_ID = 1L;
Tracer tracer = new DefaultTracer(new AlwaysSampler(), new Random(),
Mockito.mock(ApplicationEventPublisher.class));
Mockito.mock(ApplicationEventPublisher.class), new DefaultSpanNamer());
@Before
public void setup() {
@@ -49,6 +52,16 @@ public class TraceCommandTests {
then(secondSpanFromHystrix.getSavedSpan())
.as("saved span as remnant of first span").isNull();
}
@Test
public void should_create_a_local_span_with_proper_tags_when_hystrix_command_gets_executed()
throws Exception {
Span spanFromHystrix = whenCommandIsExecuted(traceReturningCommand());
then(spanFromHystrix)
.isALocalComponentSpan()
.hasNameEqualTo("traceCommandKey")
.hasATag("commandKey", "traceCommandKey");
}
@Test
public void should_run_Hystrix_command_with_span_passed_from_parent_thread() {
@@ -67,12 +80,13 @@ public class TraceCommandTests {
}
private TraceCommand<Span> traceReturningCommand() {
return new TraceCommand<Span>(this.tracer,
return new TraceCommand<Span>(this.tracer, new TraceKeys(),
withGroupKey(asKey("group"))
.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties
.Setter().withCoreSize(1).withMaxQueueSize(1))
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
.withExecutionTimeoutEnabled(false))) {
.withExecutionTimeoutEnabled(false))
.andCommandKey(HystrixCommandKey.Factory.asKey("traceCommandKey"))) {
@Override
public Span doRun() throws Exception {
return TestSpanContextHolder.getCurrentSpan();

View File

@@ -3,6 +3,7 @@ package org.springframework.cloud.sleuth.instrument.web;
import java.util.concurrent.atomic.AtomicReference;
import com.jayway.awaitility.Awaitility;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -20,8 +21,6 @@ import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.jayway.awaitility.Awaitility;
import static org.springframework.cloud.sleuth.assertions.SleuthAssertions.then;
@RunWith(SpringJUnit4ClassRunner.class)
@@ -53,9 +52,12 @@ public class TraceAsyncIntegrationTests {
Awaitility.await().until(new Runnable() {
@Override
public void run() {
then(span)
.hasTraceIdEqualTo(TraceAsyncIntegrationTests.this.classPerformingAsyncLogic.getTraceId())
.hasNameNotEqualTo(TraceAsyncIntegrationTests.this.classPerformingAsyncLogic.getSpanName());
then(TraceAsyncIntegrationTests.this.classPerformingAsyncLogic.getSpan())
.hasTraceIdEqualTo(span.getTraceId())
.hasNameEqualTo("invokeAsynchronousLogic")
.isALocalComponentSpan()
.hasATag("class", "ClassPerformingAsyncLogic")
.hasATag("method", "invokeAsynchronousLogic");
}
});
}
@@ -91,18 +93,8 @@ public class TraceAsyncIntegrationTests {
this.span.set(TestSpanContextHolder.getCurrentSpan());
}
public Long getTraceId() {
if (this.span.get() == null) {
return null;
}
return this.span.get().getTraceId();
}
public String getSpanName() {
if (this.span.get() != null && this.span.get().getName() == null) {
return null;
}
return this.span.get().getName();
public Span getSpan() {
return this.span.get();
}
}
}

View File

@@ -20,6 +20,7 @@ import java.util.Random;
import org.junit.Before;
import org.junit.Test;
import org.springframework.cloud.sleuth.DefaultSpanNamer;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.instrument.TraceKeys;
@@ -46,7 +47,7 @@ public class TraceFilterMockChainIntegrationTests {
private StaticApplicationContext context = new StaticApplicationContext();
private Tracer tracer = new DefaultTracer(new AlwaysSampler(),
new Random(), this.context);
new Random(), this.context, new DefaultSpanNamer());
private TraceKeys traceKeys = new TraceKeys();
private MockHttpServletRequest request;

View File

@@ -21,6 +21,7 @@ import java.util.Random;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.springframework.cloud.sleuth.DefaultSpanNamer;
import org.springframework.cloud.sleuth.Sampler;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
@@ -68,7 +69,7 @@ public class TraceFilterTests {
public void init() {
initMocks(this);
this.tracer = new DefaultTracer(new DelegateSampler(), new Random(),
this.publisher) {
this.publisher, new DefaultSpanNamer()) {
@Override
protected Span createSpan(Span span, Span saved) {
TraceFilterTests.this.span = super.createSpan(span, saved);

View File

@@ -16,9 +16,6 @@
package org.springframework.cloud.sleuth.instrument.web.client;
import static org.assertj.core.api.BDDAssertions.then;
import static org.junit.Assert.assertFalse;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@@ -27,6 +24,7 @@ import java.util.Random;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.cloud.sleuth.DefaultSpanNamer;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
import org.springframework.cloud.sleuth.trace.DefaultTracer;
@@ -42,6 +40,9 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import static org.assertj.core.api.BDDAssertions.then;
import static org.junit.Assert.assertFalse;
/**
* @author Dave Syer
*
@@ -61,7 +62,8 @@ public class TraceRestTemplateInterceptorTests {
@Before
public void setup() {
this.publisher.refresh();
this.traces = new DefaultTracer(new AlwaysSampler(), new Random(), this.publisher);
this.traces = new DefaultTracer(new AlwaysSampler(), new Random(), this.publisher,
new DefaultSpanNamer());
this.template.setInterceptors(Arrays.<ClientHttpRequestInterceptor>asList(
new TraceRestTemplateInterceptor(this.traces)));
TestSpanContextHolder.removeCurrentSpan();

View File

@@ -23,6 +23,7 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.cloud.sleuth.DefaultSpanNamer;
import org.springframework.cloud.sleuth.event.ClientReceivedEvent;
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
import org.springframework.cloud.sleuth.trace.DefaultTracer;
@@ -40,7 +41,9 @@ public class TracePostZuulFilterTests {
private ApplicationEventPublisher publisher = Mockito.mock(ApplicationEventPublisher.class);
private DefaultTracer tracer = new DefaultTracer(new AlwaysSampler(), new Random(), Mockito.mock(ApplicationEventPublisher.class));
private DefaultTracer tracer = new DefaultTracer(new AlwaysSampler(),
new Random(), Mockito.mock(ApplicationEventPublisher.class),
new DefaultSpanNamer());
private TracePostZuulFilter filter = new TracePostZuulFilter(this.tracer);

View File

@@ -23,6 +23,7 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.cloud.sleuth.DefaultSpanNamer;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
import org.springframework.cloud.sleuth.sampler.NeverSampler;
@@ -45,7 +46,7 @@ public class TracePreZuulFilterTests {
.mock(ApplicationEventPublisher.class);
private DefaultTracer tracer = new DefaultTracer(new AlwaysSampler(), new Random(),
this.publisher);
this.publisher, new DefaultSpanNamer());
private TracePreZuulFilter filter = new TracePreZuulFilter(this.tracer);

View File

@@ -24,7 +24,9 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.cloud.sleuth.DefaultSpanNamer;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanNamer;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.event.SpanAcquiredEvent;
import org.springframework.cloud.sleuth.event.SpanReleasedEvent;
@@ -54,6 +56,7 @@ public class DefaultTracerTests {
public static final String IMPORTANT_WORK_2 = "http:important work 2";
public static final int NUM_SPANS = 3;
private ApplicationEventPublisher publisher;
private SpanNamer spanNamer = new DefaultSpanNamer();
@Before
public void setup() {
@@ -70,7 +73,7 @@ public class DefaultTracerTests {
public void tracingWorks() {
DefaultTracer tracer = new DefaultTracer(NeverSampler.INSTANCE, new Random(),
this.publisher);
this.publisher, new DefaultSpanNamer());
Span span = tracer.startTrace(CREATE_SIMPLE_TRACE, new AlwaysSampler());
try {
@@ -109,7 +112,7 @@ public class DefaultTracerTests {
@Test
public void nonExportable() {
DefaultTracer tracer = new DefaultTracer(NeverSampler.INSTANCE, new Random(),
this.publisher);
this.publisher, this.spanNamer);
Span span = tracer.startTrace(CREATE_SIMPLE_TRACE);
assertThat(span.isExportable(), is(false));
}
@@ -117,7 +120,7 @@ public class DefaultTracerTests {
@Test
public void exportable() {
DefaultTracer tracer = new DefaultTracer(new AlwaysSampler(), new Random(),
this.publisher);
this.publisher, this.spanNamer);
Span span = tracer.startTrace(CREATE_SIMPLE_TRACE);
assertThat(span.isExportable(), is(true));
}
@@ -125,7 +128,7 @@ public class DefaultTracerTests {
@Test
public void exportableInheritedFromParent() {
DefaultTracer tracer = new DefaultTracer(new AlwaysSampler(), new Random(),
this.publisher);
this.publisher, this.spanNamer);
Span span = tracer.startTrace(CREATE_SIMPLE_TRACE, NeverSampler.INSTANCE);
assertThat(span.isExportable(), is(false));
Span child = tracer.joinTrace(CREATE_SIMPLE_TRACE_SPAN_NAME + "/child", span);
@@ -135,7 +138,7 @@ public class DefaultTracerTests {
@Test
public void parentNotRemovedIfActiveOnJoin() {
DefaultTracer tracer = new DefaultTracer(new AlwaysSampler(), new Random(),
this.publisher);
this.publisher, this.spanNamer);
Span parent = tracer.startTrace(CREATE_SIMPLE_TRACE);
Span span = tracer.joinTrace(IMPORTANT_WORK_1, parent);
tracer.close(span);
@@ -145,7 +148,7 @@ public class DefaultTracerTests {
@Test
public void parentRemovedIfNotActiveOnJoin() {
DefaultTracer tracer = new DefaultTracer(new AlwaysSampler(), new Random(),
this.publisher);
this.publisher, this.spanNamer);
Span parent = Span.builder().name(CREATE_SIMPLE_TRACE).traceId(1L).spanId(1L)
.build();
Span span = tracer.joinTrace(IMPORTANT_WORK_1, parent);
@@ -156,7 +159,7 @@ public class DefaultTracerTests {
@Test
public void grandParentRestoredAfterAutoClose() {
DefaultTracer tracer = new DefaultTracer(new AlwaysSampler(), new Random(),
this.publisher);
this.publisher, this.spanNamer);
Span grandParent = tracer.startTrace(CREATE_SIMPLE_TRACE);
Span parent = Span.builder().name(IMPORTANT_WORK_1).traceId(1L).spanId(1L)
.build();