[#146] Introduced SpanName

- Added aspect to provide better naming for @Async

fixes #146
This commit is contained in:
Marcin Grzejszczak
2016-02-09 15:25:36 +01:00
parent a0a79584f4
commit 1b0c8dfee5
54 changed files with 603 additions and 226 deletions

View File

@@ -1,7 +1,6 @@
// Do not edit this file (e.g. go instead to src/main/asciidoc)
image::https://api.travis-ci.org/spring-cloud/spring-cloud-sleuth.svg?branch=master[Build Status, link=https://travis-ci.org/spring-cloud/spring-cloud-sleuth]
image::https://badges.gitter.im/spring-cloud/spring-cloud-sleuth.svg[Gitter, link="https://gitter.im/spring-cloud/spring-cloud-sleuth?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"]
image::https://api.travis-ci.org/spring-cloud/spring-cloud-sleuth.svg?branch=master[Build Status, link=https://travis-ci.org/spring-cloud/spring-cloud-sleuth] image::https://badges.gitter.im/spring-cloud/spring-cloud-sleuth.svg[Gitter, link="https://gitter.im/spring-cloud/spring-cloud-sleuth?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"]
== Spring Cloud Sleuth
Spring Cloud Sleuth implements a distributed tracing solution for http://cloud.spring.io[Spring Cloud].

View File

@@ -61,7 +61,7 @@ public class Span {
private final long begin;
private long end = 0;
private final String name;
private final SpanName name;
private final long traceId;
@Singular
private List<Long> parents = new ArrayList<>();
@@ -93,18 +93,18 @@ public class Span {
this.savedSpan = savedSpan;
}
public Span(long begin, long end, String name, long traceId, List<Long> parents,
public Span(long begin, long end, SpanName name, long traceId, List<Long> parents,
long spanId, boolean remote, boolean exportable, String processId) {
this(begin, end, name, traceId, parents, spanId, remote, exportable, processId,
null);
}
public Span(long begin, long end, String name, long traceId, List<Long> parents,
public Span(long begin, long end, SpanName name, long traceId, List<Long> parents,
long spanId, boolean remote, boolean exportable, String processId,
Span savedSpan) {
this.begin = begin <= 0 ? System.currentTimeMillis() : begin;
this.end = end;
this.name = name;
this.name = name != null ? name : SpanName.NO_NAME;
this.traceId = traceId;
this.parents = parents;
this.spanId = spanId;
@@ -117,7 +117,7 @@ public class Span {
// for serialization
private Span() {
this.begin = 0;
this.name = null;
this.name = SpanName.NO_NAME;
this.traceId = 0;
this.spanId = 0;
this.processId = null;
@@ -210,7 +210,7 @@ public class Span {
* A human-readable name assigned to this span instance.
* <p>
*/
public String getName() {
public SpanName getName() {
return this.name;
}

View File

@@ -0,0 +1,111 @@
/*
* 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;
import java.lang.invoke.MethodHandles;
import java.util.Objects;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
/**
* Class representing a name of the span.
* It consists of
* <li>
* <ul>component - means of communication e.g. http, message</ul>
* <ul>address - what the span is addressing e.g. /some/http/address, someQueueName</ul>
* <ul>fragment - additional label e.g. async</ul>
* </li>
*
* The template of the span name is
*
* <pre>component:address#fragment</pre>
*
* @author Marcin Grzejszczak
*/
public class SpanName {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
public static final SpanName NO_NAME = new SpanName("", "");
public final String component;
public final String address;
public final String fragment;
// serialization
SpanName() {
this("", "", "");
}
public SpanName(String component, String address) {
this(component, address, "");
}
public SpanName(String component, String address, String fragment) {
this.component = component;
this.address = address;
this.fragment = fragment;
}
public static SpanName fromString(String name) {
String[] splitString = name.split(":");
if (splitString.length < 2) {
log.debug("Can't parse [{}]. Returning 'unknown' component and passing name to address", name);
return new SpanName("unknown", name);
}
String protocol = splitString[0];
String address = name.substring(name.indexOf(":") + 1);
String fragment = "";
if (address.contains("#")) {
String[] splitSecondArg = address.split("#");
fragment = address.substring(address.indexOf("#") + 1);
address = splitSecondArg[0];
}
return new SpanName(protocol, address, fragment);
}
@Override
public String toString() {
if (this.equals(NO_NAME)) {
return "";
}
String baseName = this.component + ":" + this.address;
if (StringUtils.hasText(this.fragment)) {
return baseName + "#" + this.fragment;
}
return baseName;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
SpanName spanName = (SpanName) o;
return Objects.equals(this.component, spanName.component) &&
Objects.equals(this.address, spanName.address) &&
Objects.equals(this.fragment, spanName.fragment);
}
@Override
public int hashCode() {
return Objects.hash(this.component, this.address, this.fragment);
}
}

View File

@@ -55,7 +55,7 @@ public interface Tracer extends SpanAccessor {
*
* @param name The name field for the new span to create.
*/
Span startTrace(String name);
Span startTrace(SpanName name);
/**
* Creates a new Span with a specific parent. The parent might be in another
@@ -67,7 +67,7 @@ public interface Tracer extends SpanAccessor {
*
* @param name The name field for the new span to create.
*/
Span joinTrace(String name, Span parent);
Span joinTrace(SpanName name, Span parent);
/**
* Start a new span if the sampler allows it or if we are already tracing in this
@@ -75,7 +75,7 @@ public interface Tracer extends SpanAccessor {
* @param name the name of the span
* @param sampler a sampler to decide whether to create the span or not
*/
Span startTrace(String name, Sampler sampler);
Span startTrace(SpanName name, Sampler sampler);
/**
* Pick up an existing span from another thread.

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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.scheduling.annotation.AsyncConfigurer;
@@ -47,4 +48,9 @@ public class AsyncDefaultAutoConfiguration extends AsyncConfigurerSupport {
return new LazyTraceExecutor(this.beanFactory, new SimpleAsyncTaskExecutor());
}
@Bean
public TraceAsyncAspect traceAsyncAspect(Tracer tracer) {
return new TraceAsyncAspect(tracer);
}
}

View File

@@ -0,0 +1,59 @@
/*
* 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.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.Tracer;
/**
* Aspect that creates a new Span for running threads executing methods annotated with
* {@link org.springframework.scheduling.annotation.Async} annotation.
*
* @author Marcin Grzejszczak
*
* @see Tracer
*/
@Aspect
public class TraceAsyncAspect {
private static final String ASYNC_COMPONENT = "async";
private final Tracer tracer;
public TraceAsyncAspect(Tracer tracer) {
this.tracer = tracer;
}
@Around("execution (@org.springframework.scheduling.annotation.Async * *.*(..))")
public Object traceBackgroundThread(final ProceedingJoinPoint pjp) throws Throwable {
SpanName spanName = new SpanName(ASYNC_COMPONENT,
pjp.getTarget().getClass().getSimpleName(),
"method=" + pjp.getSignature().getName());
Span span = this.tracer.startTrace(spanName);
try {
return pjp.proceed();
}
finally {
this.tracer.close(span);
}
}
}

View File

@@ -18,11 +18,11 @@ package org.springframework.cloud.sleuth.instrument.async;
import java.util.concurrent.Callable;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
import lombok.EqualsAndHashCode;
import lombok.Value;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.Tracer;
/**
* @author Spencer Gibb
@@ -35,7 +35,7 @@ public class TraceCallable<V> extends TraceDelegate<Callable<V>> implements Call
super(tracer, delegate);
}
public TraceCallable(Tracer tracer, Callable<V> delegate, String name) {
public TraceCallable(Tracer tracer, Callable<V> delegate, SpanName name) {
super(tracer, delegate, name);
}

View File

@@ -17,6 +17,7 @@
package org.springframework.cloud.sleuth.instrument.async;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.Tracer;
import lombok.Getter;
@@ -27,16 +28,18 @@ import lombok.Getter;
@Getter
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 SpanName name;
private final Span parent;
public TraceDelegate(Tracer tracer, T delegate) {
this(tracer, delegate, null);
}
public TraceDelegate(Tracer tracer, T delegate, String name) {
public TraceDelegate(Tracer tracer, T delegate, SpanName name) {
this.tracer = tracer;
this.delegate = delegate;
this.name = name;
@@ -51,8 +54,10 @@ public abstract class TraceDelegate<T> {
return this.tracer.joinTrace(getSpanName(), this.parent);
}
protected String getSpanName() {
return this.name == null ? Thread.currentThread().getName() : this.name;
protected SpanName getSpanName() {
return this.name == null ?
new SpanName(ASYNC_COMPONENT, Thread.currentThread().getName())
: this.name;
}
}

View File

@@ -16,11 +16,11 @@
package org.springframework.cloud.sleuth.instrument.async;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
import lombok.EqualsAndHashCode;
import lombok.Value;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.Tracer;
/**
* @author Spencer Gibb
@@ -33,7 +33,7 @@ public class TraceRunnable extends TraceDelegate<Runnable> implements Runnable {
super(tracer, delegate);
}
public TraceRunnable(Tracer tracer, Runnable delegate, String name) {
public TraceRunnable(Tracer tracer, Runnable delegate, SpanName name) {
super(tracer, delegate, name);
}

View File

@@ -24,6 +24,7 @@ import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.Tracer;
/**
* A decorator class for {@link ExecutorService} to support tracing in Executors
@@ -33,15 +34,21 @@ import org.springframework.cloud.sleuth.Tracer;
public class TraceableExecutorService implements ExecutorService {
final ExecutorService delegate;
final Tracer tracer;
private final SpanName spanName;
public TraceableExecutorService(final ExecutorService delegate, final Tracer tracer) {
this(delegate, tracer, null);
}
public TraceableExecutorService(final ExecutorService delegate, final Tracer tracer, SpanName spanName) {
this.delegate = delegate;
this.tracer = tracer;
this.spanName = spanName;
}
@Override
public void execute(Runnable command) {
final Runnable r = new TraceRunnable(this.tracer, command);
final Runnable r = new TraceRunnable(this.tracer, command, this.spanName);
this.delegate.execute(r);
}
@@ -72,19 +79,19 @@ public class TraceableExecutorService implements ExecutorService {
@Override
public <T> Future<T> submit(Callable<T> task) {
Callable<T> c = new TraceCallable<>(this.tracer, task);
Callable<T> c = new TraceCallable<>(this.tracer, task, this.spanName);
return this.delegate.submit(c);
}
@Override
public <T> Future<T> submit(Runnable task, T result) {
Runnable r = new TraceRunnable(this.tracer, task);
Runnable r = new TraceRunnable(this.tracer, task, this.spanName);
return this.delegate.submit(r, result);
}
@Override
public Future<?> submit(Runnable task) {
Runnable r = new TraceRunnable(this.tracer, task);
Runnable r = new TraceRunnable(this.tracer, task, this.spanName);
return this.delegate.submit(r);
}

View File

@@ -1,20 +1,20 @@
package org.springframework.cloud.sleuth.instrument.hystrix;
import java.util.concurrent.Callable;
import javax.annotation.PreDestroy;
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 lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.Tracer;
@Slf4j
public class SleuthHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {
private static final String HYSTRIX_COMPONENT = "hystrix";
private final Tracer tracer;
public SleuthHystrixConcurrencyStrategy(Tracer tracer) {
@@ -62,7 +62,8 @@ public class SleuthHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy
span = this.tracer.continueSpan(span);
}
else {
span = this.tracer.startTrace(Thread.currentThread().getName());
span = this.tracer.startTrace(new SpanName(HYSTRIX_COMPONENT,
Thread.currentThread().getName()));
created = true;
}
try {

View File

@@ -17,6 +17,7 @@
package org.springframework.cloud.sleuth.instrument.hystrix;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.Tracer;
import com.netflix.hystrix.HystrixCommand;
@@ -33,6 +34,8 @@ import com.netflix.hystrix.HystrixCommand;
*/
public abstract class TraceCommand<R> extends HystrixCommand<R> {
private static final String HYSTRIX_COMPONENT = "hystrix";
private final Tracer tracer;
private final Span parentSpan;
@@ -44,7 +47,8 @@ public abstract class TraceCommand<R> extends HystrixCommand<R> {
@Override
protected R run() throws Exception {
Span span = this.tracer.joinTrace(getCommandKey().name(), this.parentSpan);
SpanName spanName = new SpanName(HYSTRIX_COMPONENT, getCommandKey().name());
Span span = this.tracer.joinTrace(spanName, this.parentSpan);
try {
return doRun();
}

View File

@@ -3,6 +3,7 @@ package org.springframework.cloud.sleuth.instrument.messaging;
import java.util.Random;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.instrument.TraceKeys;
import org.springframework.integration.channel.AbstractMessageChannel;
@@ -20,7 +21,7 @@ import org.springframework.util.ClassUtils;
*/
abstract class AbstractTraceChannelInterceptor extends ChannelInterceptorAdapter implements ExecutorChannelInterceptor {
protected static final String MESSAGE_NAME_PREFIX = "message/";
protected static final String MESSAGE_COMPONENT = "message";
private final Tracer tracer;
@@ -64,7 +65,7 @@ abstract class AbstractTraceChannelInterceptor extends ChannelInterceptorAdapter
String processId = getHeader(message, Span.PROCESS_ID_NAME);
String spanName = getHeader(message, Span.SPAN_NAME_NAME);
if (spanName != null) {
span.name(spanName);
span.name(SpanName.fromString(spanName));
}
if (processId != null) {
span.processId(processId);
@@ -106,8 +107,8 @@ abstract class AbstractTraceChannelInterceptor extends ChannelInterceptorAdapter
return name;
}
String getMessageChannelName(MessageChannel channel) {
return MESSAGE_NAME_PREFIX + getChannelName(channel);
SpanName getMessageChannelName(MessageChannel channel) {
return new SpanName(MESSAGE_COMPONENT, getChannelName(channel));
}
}

View File

@@ -73,7 +73,7 @@ public class SpanMessageHeaders {
if (parentId != null) {
addHeader(headers, Span.PARENT_ID_NAME, Span.toHex(parentId));
}
addHeader(headers, Span.SPAN_NAME_NAME, span.getName());
addHeader(headers, Span.SPAN_NAME_NAME, span.getName().toString());
addHeader(headers, Span.PROCESS_ID_NAME, span.getProcessId());
}
else {

View File

@@ -19,6 +19,7 @@ package org.springframework.cloud.sleuth.instrument.messaging;
import java.util.Random;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.instrument.TraceKeys;
import org.springframework.cloud.sleuth.sampler.NeverSampler;
@@ -45,12 +46,12 @@ public class TraceChannelInterceptor extends AbstractTraceChannelInterceptor {
public Message<?> preSend(Message<?> message, MessageChannel channel) {
Span parentSpan = getTracer().isTracing() ? getTracer().getCurrentSpan()
: buildSpan(message);
String name = getMessageChannelName(channel);
SpanName name = getMessageChannelName(channel);
Span span = startSpan(parentSpan, name, message);
return SpanMessageHeaders.addSpanHeaders(getTraceKeys(), message, span);
}
private Span startSpan(Span span, String name, Message<?> message) {
private Span startSpan(Span span, SpanName name, Message<?> message) {
if (span != null) {
return getTracer().joinTrace(name, span);
}

View File

@@ -20,6 +20,7 @@ import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.Tracer;
/**
@@ -37,6 +38,8 @@ import org.springframework.cloud.sleuth.Tracer;
@Aspect
public class TraceSchedulingAspect {
private static final String SCHEDULED_COMPONENT = "scheduled";
private final Tracer tracer;
public TraceSchedulingAspect(Tracer tracer) {
@@ -45,7 +48,10 @@ public class TraceSchedulingAspect {
@Around("execution (@org.springframework.scheduling.annotation.Scheduled * *.*(..))")
public Object traceBackgroundThread(final ProceedingJoinPoint pjp) throws Throwable {
Span span = this.tracer.startTrace(pjp.toShortString());
SpanName spanName = new SpanName(SCHEDULED_COMPONENT,
pjp.getTarget().getClass().getSimpleName(),
"method=" + pjp.getSignature().getName());
Span span = this.tracer.startTrace(spanName);
try {
return pjp.proceed();
}

View File

@@ -31,6 +31,7 @@ import javax.servlet.http.HttpServletResponse;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Span.SpanBuilder;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.event.ServerReceivedEvent;
import org.springframework.cloud.sleuth.event.ServerSentEvent;
@@ -57,7 +58,7 @@ import org.springframework.web.util.UrlPathHelper;
*
* @see Tracer
* @see TraceKeys
* @see TraceWebAutoConfiguration#traceWebFilter(TraceFilter)
* @see TraceWebAutoConfiguration#traceFilter(TraceFilter)
*
* @author Jakub Nabrdalik, 4financeIT
* @author Tomasz Nurkiewicz, 4financeIT
@@ -117,7 +118,9 @@ public class TraceFilter extends OncePerRequestFilter
addToResponseIfNotPresent(response, Span.NOT_SAMPLED_NAME, "");
}
String name = "http" + uri;
String protocol = "http";
String address = uri;
SpanName name = new SpanName(protocol, address);
if (spanFromRequest == null) {
if (hasHeader(request, response, Span.TRACE_ID_NAME)) {
long traceId = Span
@@ -133,10 +136,10 @@ public class TraceFilter extends OncePerRequestFilter
String processId = getHeader(request, response, Span.PROCESS_ID_NAME);
String parentName = getHeader(request, response, Span.SPAN_NAME_NAME);
if (StringUtils.hasText(parentName)) {
span.name(parentName);
span.name(SpanName.fromString(parentName));
}
else {
span.name("parent/" + name);
span.name(new SpanName(protocol, "/parent" + uri));
}
if (StringUtils.hasText(processId)) {
span.processId(processId);
@@ -272,7 +275,6 @@ public class TraceFilter extends OncePerRequestFilter
private String getFullUrl(HttpServletRequest request) {
StringBuffer requestURI = request.getRequestURL();
String queryString = request.getQueryString();
if (queryString == null) {
return requestURI.toString();
}

View File

@@ -16,13 +16,15 @@
package org.springframework.cloud.sleuth.instrument.web;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.util.UrlPathHelper;
/**
* @author Spencer Gibb
@@ -33,6 +35,8 @@ public class TraceHandlerInterceptor implements HandlerInterceptor {
private final Tracer tracer;
private final UrlPathHelper urlPathHelper = new UrlPathHelper();
public TraceHandlerInterceptor(Tracer tracer) {
this.tracer = tracer;
}
@@ -42,7 +46,9 @@ public class TraceHandlerInterceptor implements HandlerInterceptor {
Object handler) throws Exception {
// TODO: get trace data from request?
// TODO: what is the description?
Span span = this.tracer.startTrace("traceHandlerInterceptor");
String uri = this.urlPathHelper.getPathWithinApplication(request);
SpanName spanName = new SpanName("http", uri, "interceptor=traceHandlerInterceptor");
Span span = this.tracer.startTrace(spanName);
request.setAttribute(ATTR_NAME, span);
return true;
}

View File

@@ -16,18 +16,20 @@
package org.springframework.cloud.sleuth.instrument.web;
import lombok.extern.apachecommons.CommonsLog;
import java.lang.reflect.Field;
import java.util.concurrent.Callable;
import org.aspectj.lang.ProceedingJoinPoint;
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.SpanName;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.instrument.async.TraceCallable;
import org.springframework.web.context.request.async.WebAsyncTask;
import java.lang.reflect.Field;
import java.util.concurrent.Callable;
import lombok.extern.apachecommons.CommonsLog;
/**
* Aspect that adds correlation id to
@@ -61,6 +63,8 @@ import java.util.concurrent.Callable;
@CommonsLog
public class TraceWebAspect {
private static final String ASYNC_COMPONENT = "async";
private final Tracer tracer;
private final SpanAccessor accessor;
@@ -100,13 +104,19 @@ public class TraceWebAspect {
if (this.accessor.isTracing()) {
log.debug("Wrapping callable with span ["
+ this.accessor.getCurrentSpan() + "]");
return new TraceCallable<>(this.tracer, callable);
return new TraceCallable<>(this.tracer, callable, spanName(pjp));
}
else {
return callable;
}
}
private SpanName spanName(ProceedingJoinPoint pjp) {
return new SpanName(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();
@@ -116,7 +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()));
callableField.set(webAsyncTask, new TraceCallable<>(this.tracer,
webAsyncTask.getCallable(), spanName(pjp)));
} catch (NoSuchFieldException ex) {
log.warn("Cannot wrap webAsyncTask's callable with TraceCallable", ex);
}

View File

@@ -126,7 +126,7 @@ public class TraceFeignClientAutoConfiguration {
return;
}
template.header(Span.TRACE_ID_NAME, Span.toHex(span.getTraceId()));
setHeader(template, Span.SPAN_NAME_NAME, span.getName());
setHeader(template, Span.SPAN_NAME_NAME, span.getName().toString());
setHeader(template, Span.SPAN_ID_NAME, Span.toHex(span.getSpanId()));
if (!span.isExportable()) {
setHeader(template, Span.NOT_SAMPLED_NAME, "true");
@@ -152,18 +152,12 @@ public class TraceFeignClientAutoConfiguration {
}
public void setHeader(RequestTemplate request, String name, String value) {
if (value != null && !request.headers().containsKey(name)
if (StringUtils.hasText(value) && !request.headers().containsKey(name)
&& this.accessor.isTracing()) {
request.header(name, value);
}
}
public void setHeader(RequestTemplate request, String name, Long value) {
if (value != null) {
setHeader(request, name, Span.toHex(value));
}
}
private Map<String, Collection<String>> headersWithTraceId(
Map<String, Collection<String>> headers) {
Map<String, Collection<String>> newHeaders = new HashMap<>();

View File

@@ -28,6 +28,7 @@ import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.StringUtils;
/**
* Interceptor that verifies whether the trance and span id has been set on the request
@@ -68,7 +69,7 @@ public class TraceRestTemplateInterceptor
if (!span.isExportable()) {
setHeader(request, Span.NOT_SAMPLED_NAME, "true");
}
setHeader(request, Span.SPAN_NAME_NAME, span.getName());
setHeader(request, Span.SPAN_NAME_NAME, span.getName().toString());
setHeader(request, Span.PARENT_ID_NAME, getParentId(span));
setHeader(request, Span.PROCESS_ID_NAME, span.getProcessId());
publish(new ClientSentEvent(this, span));
@@ -93,7 +94,7 @@ public class TraceRestTemplateInterceptor
}
public void setHeader(HttpRequest request, String name, String value) {
if (value!=null && !request.getHeaders().containsKey(name) && this.accessor.isTracing()) {
if (StringUtils.hasText(value) && !request.getHeaders().containsKey(name) && this.accessor.isTracing()) {
request.getHeaders().add(name, value);
}
}

View File

@@ -28,6 +28,7 @@ import org.springframework.util.ReflectionUtils;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.springframework.util.StringUtils;
/**
* @author Dave Syer
@@ -68,7 +69,7 @@ public class TracePreZuulFilter extends ZuulFilter
try {
setHeader(response, Span.SPAN_ID_NAME, span.getSpanId());
setHeader(response, Span.TRACE_ID_NAME, span.getTraceId());
setHeader(response, Span.SPAN_NAME_NAME, span.getName());
setHeader(response, Span.SPAN_NAME_NAME, span.getName().toString());
if (!span.isExportable()) {
setHeader(response, Span.NOT_SAMPLED_NAME, "true");
}
@@ -92,7 +93,7 @@ public class TracePreZuulFilter extends ZuulFilter
}
public void setHeader(Map<String, String> request, String name, String value) {
if (value != null && !request.containsKey(name) && this.accessor.isTracing()) {
if (StringUtils.hasText(value) && !request.containsKey(name) && this.accessor.isTracing()) {
request.put(name, value);
}
}

View File

@@ -97,7 +97,7 @@ public class TraceRestClientRibbonCommandFactory extends RestClientRibbonCommand
}
setHeader(requestBuilder, Span.TRACE_ID_NAME, Span.toHex(span.getTraceId()));
setHeader(requestBuilder, Span.SPAN_ID_NAME, Span.toHex(span.getSpanId()));
setHeader(requestBuilder, Span.SPAN_NAME_NAME, span.getName());
setHeader(requestBuilder, Span.SPAN_NAME_NAME, span.getName().toString());
setHeader(requestBuilder, Span.PARENT_ID_NAME,
Span.toHex(getParentId(span)));
setHeader(requestBuilder, Span.PROCESS_ID_NAME,

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.SpanName;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.event.SpanAcquiredEvent;
import org.springframework.cloud.sleuth.event.SpanContinuedEvent;
@@ -49,7 +50,7 @@ public class DefaultTracer implements Tracer {
}
@Override
public Span joinTrace(String name, Span parent) {
public Span joinTrace(SpanName name, Span parent) {
if (parent == null) {
return startTrace(name);
}
@@ -57,12 +58,12 @@ public class DefaultTracer implements Tracer {
}
@Override
public Span startTrace(String name) {
public Span startTrace(SpanName name) {
return this.startTrace(name, this.defaultSampler);
}
@Override
public Span startTrace(String name, Sampler sampler) {
public Span startTrace(SpanName name, Sampler sampler) {
Span span;
if (isTracing()) {
span = createChild(getCurrentSpan(), name);
@@ -128,7 +129,7 @@ public class DefaultTracer implements Tracer {
return savedSpan;
}
protected Span createChild(Span parent, String name) {
protected Span createChild(Span parent, SpanName name) {
long id = createId();
if (parent == null) {
Span span = Span.builder().begin(System.currentTimeMillis()).name(name)

View File

@@ -0,0 +1,51 @@
package org.springframework.cloud.sleuth;
import org.junit.Test;
import static org.springframework.cloud.sleuth.assertions.SleuthAssertions.then;
/**
* @author Marcin Grzejszczak
*/
public class SpanNameTest {
@Test
public void should_return_span_name_wihout_fragment_when_no_fragment_is_passed() {
then(new SpanName("component", "address").toString())
.isEqualTo("component:address");
}
@Test
public void should_return_span_name_together_with_fragment_when_fragment_was_passed() {
then(new SpanName("component", "address", "fragment").toString())
.isEqualTo("component:address#fragment");
}
@Test
public void should_return_empty_string_if_there_is_no_span_name() {
then(SpanName.NO_NAME.toString()).isEmpty();
}
@Test
public void should_build_span_from_valid_string_name() {
then(SpanName.fromString("http:/a/b/c#async"))
.hasComponentEqualTo("http")
.hasAddressEqualTo("/a/b/c")
.hasFragmentEqualTo("async");
}
@Test
public void should_build_span_from_a_string_with_missing_protocol() {
then(SpanName.fromString("/a/b/c").toString())
.isEqualTo("unknown:/a/b/c");
}
@Test
public void should_build_span_from_a_string_name_with_many_separators() {
then(SpanName.fromString("http:/a/b:/c#async:asd=123#4444"))
.hasComponentEqualTo("http")
.hasAddressEqualTo("/a/b:/c")
.hasFragmentEqualTo("async:asd=123#4444");
}
}

View File

@@ -1,9 +1,9 @@
package org.springframework.cloud.sleuth;
import org.junit.Test;
import java.util.Collections;
import org.junit.Test;
import static org.assertj.core.api.BDDAssertions.then;
/**
@@ -37,14 +37,14 @@ public class SpanTest {
}
@Test(expected = UnsupportedOperationException.class) public void getAnnotationsReadOnly() {
Span span = new Span(1, 2, "name", 1L, Collections.<Long>emptyList(), 2L, true,
Span span = new Span(1, 2, new SpanName("http", "name"), 1L, Collections.<Long>emptyList(), 2L, true,
true, "process");
span.tags().put("a", "b");
}
@Test(expected = UnsupportedOperationException.class) public void getTimelineAnnotationsReadOnly() {
Span span = new Span(1, 2, "name", 1L, Collections.<Long>emptyList(), 2L, true,
Span span = new Span(1, 2, new SpanName("http", "name"), 1L, Collections.<Long>emptyList(), 2L, true,
true, "process");
span.logs().add(new Log(1, "1"));

View File

@@ -2,6 +2,7 @@ package org.springframework.cloud.sleuth.assertions;
import org.assertj.core.api.BDDAssertions;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanName;
public class SleuthAssertions extends BDDAssertions {
@@ -13,4 +14,12 @@ public class SleuthAssertions extends BDDAssertions {
return new SpanAssert(actual);
}
public static SpanNameAssert then(SpanName actual) {
return assertThat(actual);
}
public static SpanNameAssert assertThat(SpanName actual) {
return new SpanNameAssert(actual);
}
}

View File

@@ -6,6 +6,7 @@ import org.assertj.core.api.AbstractAssert;
import org.springframework.cloud.sleuth.Span;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.sleuth.SpanName;
@Slf4j
public class SpanAssert extends AbstractAssert<SpanAssert, Span> {
@@ -28,7 +29,7 @@ public class SpanAssert extends AbstractAssert<SpanAssert, Span> {
return this;
}
public SpanAssert hasNameNotEqualTo(String name) {
public SpanAssert hasNameNotEqualTo(SpanName name) {
isNotNull();
if (Objects.equals(this.actual.getName(), name)) {
String message = String.format("Expected span's name not to be <%s> but was <%s>", name, this.actual.getName());
@@ -38,7 +39,7 @@ public class SpanAssert extends AbstractAssert<SpanAssert, Span> {
return this;
}
public SpanAssert hasNameEqualTo(String name) {
public SpanAssert hasNameEqualTo(SpanName name) {
isNotNull();
if (!Objects.equals(this.actual.getName(), name)) {
String message = String.format("Expected span's name to be <%s> but it was <%s>", name, this.actual.getName());

View File

@@ -0,0 +1,66 @@
/*
* 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.assertions;
import java.util.Objects;
import org.assertj.core.api.AbstractAssert;
import org.springframework.cloud.sleuth.SpanName;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class SpanNameAssert extends AbstractAssert<SpanNameAssert, SpanName> {
public SpanNameAssert(SpanName actual) {
super(actual, SpanNameAssert.class);
}
public static SpanNameAssert then(SpanName actual) {
return new SpanNameAssert(actual);
}
public SpanNameAssert hasComponentEqualTo(String protocol) {
isNotNull();
if (!Objects.equals(this.actual.component, protocol)) {
String message = String.format("Expected span name's component to be <%s> but was <%s>", protocol, this.actual.component);
log.error(message);
failWithMessage(message);
}
return this;
}
public SpanNameAssert hasAddressEqualTo(String address) {
isNotNull();
if (!Objects.equals(this.actual.address, address)) {
String message = String.format("Expected span name's address to be <%s> but was <%s>", address, this.actual.address);
log.error(message);
failWithMessage(message);
}
return this;
}
public SpanNameAssert hasFragmentEqualTo(String fragment) {
isNotNull();
if (!Objects.equals(this.actual.fragment, fragment)) {
String message = String.format("Expected span name's fragment to be <%s> but was <%s>", fragment, this.actual.fragment);
log.error(message);
failWithMessage(message);
}
return this;
}
}

View File

@@ -1,11 +1,17 @@
package org.springframework.cloud.sleuth.instrument.async;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
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.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;
@@ -13,11 +19,6 @@ 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.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import static org.assertj.core.api.BDDAssertions.then;
@RunWith(MockitoJUnitRunner.class)
@@ -72,7 +73,7 @@ public class TraceCallableTests {
}
private Span givenSpanIsAlreadyActive() {
return this.tracer.startTrace("parent");
return this.tracer.startTrace(new SpanName("http", "parent"));
}
private Callable<Span> thatRetrievesTraceFromThreadLocal() {

View File

@@ -1,20 +1,5 @@
package org.springframework.cloud.sleuth.instrument.async;
import lombok.SneakyThrows;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
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.Tracer;
import org.springframework.cloud.sleuth.instrument.async.TraceableExecutorService;
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.ArrayList;
import java.util.List;
import java.util.Queue;
@@ -24,6 +9,22 @@ import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import lombok.SneakyThrows;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
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.SpanName;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.instrument.async.TraceableExecutorService;
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 java.util.stream.Collectors.toList;
import static org.assertj.core.api.BDDAssertions.then;
@@ -55,7 +56,7 @@ public class TraceableExecutorServiceTests {
@Test
@SneakyThrows
public void should_propagate_trace_id_and_set_new_span_when_traceable_executor_service_is_executed() {
Span span = this.tracer.startTrace("PARENT");
Span span = this.tracer.startTrace(new SpanName("http", "PARENT"));
CompletableFuture.allOf(runnablesExecutedViaTraceManagerableExecutorService()).get();
this.tracer.close(span);

View File

@@ -10,6 +10,7 @@ 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.Span;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.instrument.DefaultTestAutoConfiguration;
import org.springframework.cloud.sleuth.trace.TestSpanContextHolder;
@@ -57,7 +58,7 @@ public class HystrixAnnotationsIntegrationTests {
}
private Span givenASpanInCurrentThread() {
Span span = this.tracer.startTrace("existing");
Span span = this.tracer.startTrace(new SpanName("http", "existing"));
this.tracer.continueSpan(span);
return span;
}
@@ -111,11 +112,11 @@ public class HystrixAnnotationsIntegrationTests {
return this.spanCaughtFromHystrixThread.get().getTraceId();
}
public String getSpanName() {
public SpanName getSpanName() {
if (this.spanCaughtFromHystrixThread == null
|| (this.spanCaughtFromHystrixThread.get() != null
&& this.spanCaughtFromHystrixThread.get()
.getName() == null)) {
&& this.spanCaughtFromHystrixThread.get()
.getName() == null)) {
return null;
}
return this.spanCaughtFromHystrixThread.get().getName();

View File

@@ -1,9 +1,5 @@
package org.springframework.cloud.sleuth.instrument.hystrix;
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 java.util.Random;
import org.junit.After;
@@ -11,6 +7,7 @@ import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
import org.springframework.cloud.sleuth.trace.DefaultTracer;
@@ -21,6 +18,10 @@ import com.netflix.hystrix.HystrixCommandProperties;
import com.netflix.hystrix.HystrixThreadPoolProperties;
import com.netflix.hystrix.strategy.HystrixPlugins;
import static com.netflix.hystrix.HystrixCommand.Setter.withGroupKey;
import static com.netflix.hystrix.HystrixCommandGroupKey.Factory.asKey;
import static org.assertj.core.api.BDDAssertions.then;
public class TraceCommandTests {
static final long EXPECTED_TRACE_ID = 1L;
@@ -63,7 +64,7 @@ public class TraceCommandTests {
}
private Span givenATraceIsPresentInTheCurrentThread() {
return this.tracer.joinTrace("test",
return this.tracer.joinTrace(new SpanName("http", "test"),
Span.builder().traceId(EXPECTED_TRACE_ID).build());
}
@@ -72,8 +73,8 @@ public class TraceCommandTests {
withGroupKey(asKey("group"))
.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties
.Setter().withCoreSize(1).withMaxQueueSize(1))
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
.withExecutionTimeoutEnabled(false))) {
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
.withExecutionTimeoutEnabled(false))) {
@Override
public Span doRun() throws Exception {
return TestSpanContextHolder.getCurrentSpan();

View File

@@ -20,6 +20,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.instrument.TraceKeys;
import org.springframework.messaging.Message;
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
@@ -38,7 +39,7 @@ public class SpanMessageHeadersTests {
@Test
public void spanHeadersAdded() {
Span span = Span.builder().name("foo").spanId(1L).traceId(2L).build();
Span span = Span.builder().name(new SpanName("http", "foo")).spanId(1L).traceId(2L).build();
Message<?> message = new GenericMessage<>("Hello World");
message = SpanMessageHeaders.addSpanHeaders(this.traceKeys, message, span);
assertThat(message.getHeaders()).containsKey(Span.SPAN_ID_NAME);
@@ -46,7 +47,7 @@ public class SpanMessageHeadersTests {
@Test
public void nativeSpanHeadersAdded() {
Span span = Span.builder().name("foo").spanId(1L).traceId(2L).build();
Span span = Span.builder().name(new SpanName("http", "foo")).spanId(1L).traceId(2L).build();
MessageHeaderAccessor accessor = SimpMessageHeaderAccessor.create();
Message<?> message = MessageBuilder.createMessage("Hello World", accessor.getMessageHeaders());
message = SpanMessageHeaders.addSpanHeaders(this.traceKeys, message, span);

View File

@@ -16,12 +16,6 @@
package org.springframework.cloud.sleuth.instrument.messaging;
import static org.assertj.core.api.BDDAssertions.then;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import java.util.ArrayList;
import java.util.List;
@@ -35,6 +29,7 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.IntegrationTest;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.event.SpanReleasedEvent;
import org.springframework.cloud.sleuth.instrument.messaging.TraceChannelInterceptorTests.App;
@@ -52,6 +47,12 @@ import org.springframework.messaging.MessagingException;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.assertj.core.api.BDDAssertions.then;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
/**
* @author Dave Syer
*/
@@ -138,7 +139,7 @@ public class TraceChannelInterceptorTests implements MessageHandler {
@Test
public void headerCreation() {
Span span = this.tracer.startTrace("testSendMessage", new AlwaysSampler());
Span span = this.tracer.startTrace(new SpanName("http", "testSendMessage"), new AlwaysSampler());
this.channel.send(MessageBuilder.withPayload("hi").build());
this.tracer.close(span);
assertNotNull("message was null", this.message);
@@ -154,7 +155,7 @@ public class TraceChannelInterceptorTests implements MessageHandler {
// TODO: Refactor to parametrized test together with sending messages via channel
@Test
public void headerCreationViaMessagingTemplate() {
Span span = this.tracer.startTrace("testSendMessage", new AlwaysSampler());
Span span = this.tracer.startTrace(new SpanName("http", "testSendMessage"), new AlwaysSampler());
this.messagingTemplate.send(MessageBuilder.withPayload("hi").build());
this.tracer.close(span);
assertNotNull("message was null", this.message);

View File

@@ -25,6 +25,7 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.IntegrationTest;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.instrument.messaging.TraceContextPropagationChannelInterceptorTests.App;
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
@@ -65,7 +66,7 @@ public class TraceContextPropagationChannelInterceptorTests {
@Test
public void testSpanPropagation() {
Span span = this.tracer.startTrace("testSendMessage", new AlwaysSampler());
Span span = this.tracer.startTrace(new SpanName("http", "testSendMessage"), new AlwaysSampler());
this.channel.send(MessageBuilder.withPayload("hi").build());
Long expectedSpanId = span.getSpanId();
this.tracer.close(span);

View File

@@ -1,13 +1,15 @@
package org.springframework.cloud.sleuth.instrument.web;
import com.jayway.awaitility.Awaitility;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.After;
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.sleuth.Span;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.instrument.DefaultTestAutoConfiguration;
import org.springframework.cloud.sleuth.trace.TestSpanContextHolder;
@@ -17,7 +19,7 @@ import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.concurrent.atomic.AtomicReference;
import com.jayway.awaitility.Awaitility;
import static org.springframework.cloud.sleuth.assertions.SleuthAssertions.then;
@@ -39,7 +41,7 @@ public class TraceAsyncIntegrationTests {
}
private Span givenASpanInCurrentThread() {
Span span = this.tracer.startTrace("existing");
Span span = this.tracer.startTrace(new SpanName("http", "existing"));
this.tracer.continueSpan(span);
return span;
}
@@ -55,6 +57,8 @@ public class TraceAsyncIntegrationTests {
then(span)
.hasTraceIdEqualTo(TraceAsyncIntegrationTests.this.classPerformingAsyncLogic.getTraceId())
.hasNameNotEqualTo(TraceAsyncIntegrationTests.this.classPerformingAsyncLogic.getSpanName());
then(TraceAsyncIntegrationTests.this.classPerformingAsyncLogic.getSpanName()).
isEqualTo(SpanName.fromString("async:ClassPerformingAsyncLogic#method=invokeAsynchronousLogic"));
}
});
}
@@ -92,7 +96,7 @@ public class TraceAsyncIntegrationTests {
return this.span.get().getTraceId();
}
public String getSpanName() {
public SpanName getSpanName() {
if (this.span.get() != null && this.span.get().getName() == null) {
return null;
}

View File

@@ -16,21 +16,15 @@
package org.springframework.cloud.sleuth.instrument.web;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.mockito.MockitoAnnotations.initMocks;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import java.util.Random;
import lombok.SneakyThrows;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.springframework.cloud.sleuth.Sampler;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.instrument.TraceKeys;
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
@@ -46,7 +40,13 @@ import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockServletContext;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import lombok.SneakyThrows;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.mockito.MockitoAnnotations.initMocks;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
/**
* @author Spencer Gibb
@@ -113,8 +113,7 @@ public class TraceFilterTests {
@Test
public void continuesSpanInRequestAttr() throws Exception {
Span span = this.tracer.startTrace("foo");
Span span = this.tracer.startTrace(new SpanName("http", "foo"));
this.request.setAttribute(TraceFilter.TRACE_REQUEST_ATTR, span);
// It should have been removed from the thread local context so simulate that
TestSpanContextHolder.removeCurrentSpan();

View File

@@ -6,6 +6,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.sleuth.Sampler;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.event.ArrayListSpanAccumulator;
import org.springframework.cloud.sleuth.instrument.TraceKeys;
@@ -44,9 +45,11 @@ public class MultipleHopsIntegrationTests extends AbstractMvcIntegrationTest {
MockMvcResultMatchers.status().isOk());
await().until(() -> {
then(this.arrayListSpanAccumulator.getSpans().stream().map(Span::getName).collect(
toList())).containsAll(asList("http/greeting", "message/greetings",
"message/words", "message/counts"));
then(this.arrayListSpanAccumulator.getSpans().stream().map(Span::getName)
.map(SpanName::toString)
.collect(
toList())).containsAll(asList("http:/greeting", "message:greetings",
"message:words", "message:counts"));
});
}

View File

@@ -16,22 +16,22 @@
package org.springframework.cloud.sleuth.instrument.zuul;
import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.verify;
import java.util.Random;
import com.netflix.zuul.context.RequestContext;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.event.ClientReceivedEvent;
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 com.netflix.zuul.context.RequestContext;
import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.verify;
/**
* @author Dave Syer
@@ -55,7 +55,7 @@ public class TracePostZuulFilterTests {
@Test
public void filterPublishesEvent() throws Exception {
this.filter.setApplicationEventPublisher(this.publisher);
this.tracer.startTrace("start");
this.tracer.startTrace(new SpanName("http", "start"));
this.filter.run();
verify(this.publisher).publishEvent(isA(ClientReceivedEvent.class));
}

View File

@@ -16,25 +16,25 @@
package org.springframework.cloud.sleuth.instrument.zuul;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat;
import java.util.Random;
import com.netflix.zuul.context.RequestContext;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
import org.springframework.cloud.sleuth.sampler.NeverSampler;
import org.springframework.cloud.sleuth.trace.DefaultTracer;
import org.springframework.cloud.sleuth.trace.TestSpanContextHolder;
import org.springframework.context.ApplicationEventPublisher;
import com.netflix.zuul.context.RequestContext;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat;
/**
* @author Dave Syer
@@ -59,7 +59,7 @@ public class TracePreZuulFilterTests {
@Test
public void filterAddsHeaders() throws Exception {
this.tracer.startTrace("start");
this.tracer.startTrace(new SpanName("http", "start"));
this.filter.run();
RequestContext ctx = RequestContext.getCurrentContext();
assertThat(ctx.getZuulRequestHeaders().get(Span.TRACE_ID_NAME),
@@ -70,7 +70,7 @@ public class TracePreZuulFilterTests {
@Test
public void notSampledIfNotExportable() throws Exception {
this.tracer.startTrace("start", NeverSampler.INSTANCE);
this.tracer.startTrace(new SpanName("http", "start"), NeverSampler.INSTANCE);
this.filter.run();
RequestContext ctx = RequestContext.getCurrentContext();
assertThat(ctx.getZuulRequestHeaders().get(Span.TRACE_ID_NAME),

View File

@@ -16,15 +16,6 @@
package org.springframework.cloud.sleuth.trace;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
@@ -34,6 +25,7 @@ import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.event.SpanAcquiredEvent;
import org.springframework.cloud.sleuth.event.SpanReleasedEvent;
@@ -42,14 +34,25 @@ import org.springframework.cloud.sleuth.sampler.NeverSampler;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
/**
* @author Spencer Gibb
*/
public class DefaultTracerTests {
public static final String CREATE_SIMPLE_TRACE = "createSimpleTrace";
public static final String IMPORTANT_WORK_1 = "important work 1";
public static final String IMPORTANT_WORK_2 = "important work 2";
public static final String CREATE_SIMPLE_TRACE_SPAN_NAME = "createSimpleTrace";
public static final SpanName CREATE_SIMPLE_TRACE = new SpanName("http",
CREATE_SIMPLE_TRACE_SPAN_NAME);
public static final SpanName IMPORTANT_WORK_1 = new SpanName("http", "important work 1");
public static final SpanName IMPORTANT_WORK_2 = new SpanName("http", "important work 2");
public static final int NUM_SPANS = 3;
private ApplicationEventPublisher publisher;
@@ -126,7 +129,7 @@ public class DefaultTracerTests {
this.publisher);
Span span = tracer.startTrace(CREATE_SIMPLE_TRACE, NeverSampler.INSTANCE);
assertThat(span.isExportable(), is(false));
Span child = tracer.joinTrace(CREATE_SIMPLE_TRACE + "/child", span);
Span child = tracer.joinTrace(new SpanName("http", CREATE_SIMPLE_TRACE_SPAN_NAME + "/child"), span);
assertThat(child.isExportable(), is(false));
}
@@ -163,7 +166,7 @@ public class DefaultTracerTests {
assertThat(tracer.getCurrentSpan(), is(equalTo(grandParent)));
}
private Span assertSpan(List<Span> spans, Long parentId, String name) {
private Span assertSpan(List<Span> spans, Long parentId, SpanName name) {
List<Span> found = findSpans(spans, parentId);
assertThat("more than one span with parentId " + parentId, found.size(), is(1));
Span span = found.get(0);

View File

@@ -21,7 +21,6 @@ import java.util.Optional;
import java.util.Random;
import java.util.stream.Collectors;
import integration.MessagingApplicationTests.IntegrationSpanCollectorConfig;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -33,6 +32,8 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import integration.MessagingApplicationTests.IntegrationSpanCollectorConfig;
import sample.SampleMessagingApplication;
import tools.AbstractIntegrationTest;
import zipkin.Constants;
@@ -116,7 +117,7 @@ public class MessagingApplicationTests extends AbstractIntegrationTest {
private Optional<Span> findLastHttpSpan() {
return this.integrationTestSpanCollector.hashedSpans.stream()
.filter(span -> "http/foo".equals(span.name)).findFirst();
.filter(span -> "http:/foo".equals(span.name)).findFirst();
}
private Optional<Span> findSpanWithAnnotation(List<Span> eventSpans, String annotationName) {
@@ -128,13 +129,13 @@ public class MessagingApplicationTests extends AbstractIntegrationTest {
private List<Span> findAllEventRelatedSpans() {
return this.integrationTestSpanCollector.hashedSpans.stream()
.filter(span -> "message/messages".equals(span.name) && span.parentId != null).collect(
.filter(span -> "message:messages".equals(span.name) && span.parentId != null).collect(
Collectors.toList());
}
private Optional<Span> findFirstHttpRequestSpan() {
return this.integrationTestSpanCollector.hashedSpans.stream()
.filter(span -> "http/".equals(span.name) && span.parentId != null).findFirst();
.filter(span -> "http:/".equals(span.name) && span.parentId != null).findFirst();
}
private void thenAllSpansArePresent(Optional<Span> firstHttpSpan,

View File

@@ -16,12 +16,16 @@
package sample;
import java.util.Random;
import java.util.concurrent.Callable;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanAccessor;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
import org.springframework.context.ApplicationListener;
@@ -29,9 +33,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.Random;
import java.util.concurrent.Callable;
/**
* @author Spencer Gibb
*/
@@ -93,7 +94,7 @@ ApplicationListener<EmbeddedServletContainerInitializedEvent> {
@SneakyThrows
@RequestMapping("/traced")
public String traced() {
Span span = this.tracer.startTrace("customTraceEndpoint",
Span span = this.tracer.startTrace(new SpanName("http", "customTraceEndpoint"),
new AlwaysSampler());
int millis = this.random.nextInt(1000);
log.info("Sleeping for {} millis", millis);

View File

@@ -15,6 +15,9 @@
*/
package integration;
import java.util.Collections;
import java.util.Random;
import example.ZipkinStreamServerApplication;
import org.junit.Before;
import org.junit.Test;
@@ -25,6 +28,7 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.boot.test.WebIntegrationTest;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.stream.Host;
import org.springframework.cloud.sleuth.stream.SleuthSink;
import org.springframework.cloud.sleuth.stream.Spans;
@@ -36,9 +40,6 @@ import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import tools.AbstractIntegrationTest;
import java.util.Collections;
import java.util.Random;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = { TestSupportBinderAutoConfiguration.class,
ZipkinStreamServerApplication.class })
@@ -62,7 +63,7 @@ public class ZipkinStreamTests extends AbstractIntegrationTest {
@Test
public void should_propagate_spans_to_zipkin() {
Span span = Span.builder().traceId(this.traceId).spanId(this.spanId).name("test").build();
Span span = Span.builder().traceId(this.traceId).spanId(this.spanId).name(new SpanName("http", "test")).build();
span.tag(getRequiredBinaryAnnotationName(), "10131");
this.input.send(messageWithSpan(span));

View File

@@ -23,6 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanAccessor;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
import org.springframework.context.ApplicationListener;
@@ -96,7 +97,7 @@ ApplicationListener<EmbeddedServletContainerInitializedEvent> {
@SneakyThrows
@RequestMapping("/traced")
public String traced() {
Span span = this.tracer.startTrace("customTraceEndpoint",
Span span = this.tracer.startTrace(new SpanName("http", "customTraceEndpoint"),
new AlwaysSampler());
int millis = this.random.nextInt(1000);
log.info("Sleeping for {} millis", millis);

View File

@@ -16,12 +16,16 @@
package sample;
import java.util.Random;
import java.util.concurrent.Callable;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanAccessor;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
import org.springframework.context.ApplicationListener;
@@ -29,9 +33,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.Random;
import java.util.concurrent.Callable;
/**
* @author Spencer Gibb
*/
@@ -93,7 +94,7 @@ ApplicationListener<EmbeddedServletContainerInitializedEvent> {
@SneakyThrows
@RequestMapping("/traced")
public String traced() {
Span span = this.tracer.startTrace("customTraceEndpoint",
Span span = this.tracer.startTrace(new SpanName("http", "customTraceEndpoint"),
new AlwaysSampler());
int millis = this.random.nextInt(1000);
log.info("Sleeping for {} millis", millis);

View File

@@ -16,18 +16,19 @@
package org.springframework.cloud.sleuth.stream;
import org.junit.Test;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.cloud.sleuth.Span;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Collections;
import org.junit.Test;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanName;
import static org.assertj.core.api.Assertions.assertThat;
public class ServerPropertiesHostLocatorTests {
Span span = new Span(1, 3, "name", 1L, Collections.<Long>emptyList(), 2L, true, true,
Span span = new Span(1, 3, new SpanName("http", "name"), 1L, Collections.<Long>emptyList(), 2L, true, true,
"process");
@Test

View File

@@ -35,6 +35,7 @@ import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfigurati
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.cloud.sleuth.Sampler;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration;
import org.springframework.cloud.sleuth.event.ClientReceivedEvent;
@@ -75,16 +76,16 @@ public class StreamSpanListenerTests {
@Test
public void acquireAndRelease() {
Span context = this.tracer.startTrace("foo");
Span context = this.tracer.startTrace(new SpanName("http", "foo"));
this.tracer.close(context);
assertEquals(1, this.test.spans.size());
}
@Test
public void rpcAnnotations() {
Span parent = Span.builder().traceId(1L).name("parent").remote(true)
Span parent = Span.builder().traceId(1L).name(new SpanName("http", "parent")).remote(true)
.build();
Span context = this.tracer.joinTrace("child", parent);
Span context = this.tracer.joinTrace(new SpanName("http", "child"), parent);
this.application.publishEvent(new ClientSentEvent(this, context));
this.application
.publishEvent(new ServerReceivedEvent(this, parent, context));
@@ -107,7 +108,7 @@ public class StreamSpanListenerTests {
@Test
public void shouldIncreaseNumberOfAcceptedSpans() {
Span context = this.tracer.startTrace("foo");
Span context = this.tracer.startTrace(new SpanName("http", "foo"));
this.tracer.close(context);
this.listener.poll();

View File

@@ -18,13 +18,12 @@ package org.springframework.cloud.sleuth.zipkin.stream;
import java.util.Iterator;
import java.util.NoSuchElementException;
import lombok.extern.apachecommons.CommonsLog;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.stream.Host;
import org.springframework.cloud.sleuth.stream.SleuthSink;
import org.springframework.cloud.sleuth.stream.Spans;
import org.springframework.util.StringUtils;
import lombok.extern.apachecommons.CommonsLog;
import zipkin.BinaryAnnotation;
import zipkin.Constants;
import zipkin.Endpoint;
@@ -37,6 +36,8 @@ import zipkin.Span.Builder;
@CommonsLog
final class SamplingZipkinSpanIterator implements Iterator<zipkin.Span> {
private static final String MESSAGE_COMPONENT = "message";
private final Sampler sampler;
private final Iterator<Span> delegate;
private final Host host;
@@ -75,7 +76,7 @@ final class SamplingZipkinSpanIterator implements Iterator<zipkin.Span> {
* returns a converted span or null if it is invalid or unsampled.
*/
zipkin.Span convertAndSample(Span input, Host host) {
if (!input.getName().equals("message/" + SleuthSink.INPUT)) {
if (!protocolWithAddressMatch(input)) {
zipkin.Span result = SamplingZipkinSpanIterator.convert(input, host);
if (this.sampler.isSampled(result.traceId)) {
return result;
@@ -87,6 +88,12 @@ final class SamplingZipkinSpanIterator implements Iterator<zipkin.Span> {
return null;
}
private boolean protocolWithAddressMatch(Span input) {
SpanName spanName = input.getName();
return SamplingZipkinSpanIterator.MESSAGE_COMPONENT.equals(spanName.component) &&
("/" + SleuthSink.INPUT).equals(spanName.address);
}
/**
* Converts a given Sleuth span to a Zipkin Span.
* <ul>
@@ -128,8 +135,8 @@ final class SamplingZipkinSpanIterator implements Iterator<zipkin.Span> {
zipkinSpan.parentId(span.getParents().get(0));
}
zipkinSpan.id(span.getSpanId());
if (StringUtils.hasText(span.getName())) {
zipkinSpan.name(span.getName());
if (!SpanName.NO_NAME.equals(span.getName())) {
zipkinSpan.name(span.getName().toString());
}
return zipkinSpan.build();
}

View File

@@ -15,18 +15,19 @@
*/
package org.springframework.cloud.sleuth.zipkin.stream;
import org.junit.Test;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.stream.Host;
import org.springframework.cloud.sleuth.stream.Spans;
import zipkin.Sampler;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.Test;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.stream.Host;
import org.springframework.cloud.sleuth.stream.Spans;
import zipkin.Sampler;
import static org.assertj.core.api.Assertions.assertThat;
public class SamplingZipkinSpanIteratorTests {
@@ -36,7 +37,7 @@ public class SamplingZipkinSpanIteratorTests {
@Test
public void skipsInputSpans() {
Spans spans = new Spans(this.host,
Collections.singletonList(span("message/sleuth")));
Collections.singletonList(span("sleuth")));
Iterator<zipkin.Span> result = new SamplingZipkinSpanIterator(
Sampler.create(1.0f), spans);
@@ -52,7 +53,8 @@ public class SamplingZipkinSpanIteratorTests {
Iterator<zipkin.Span> result = new SamplingZipkinSpanIterator(
Sampler.create(1.0f), spans);
assertThat(result).extracting(s -> s.name).containsExactly("foo", "bar", "baz");
assertThat(result).extracting(s -> s.name).containsExactly(
"message:/foo", "message:/bar", "message:/baz");
}
@Test
@@ -71,12 +73,13 @@ public class SamplingZipkinSpanIteratorTests {
Iterator<zipkin.Span> result = new SamplingZipkinSpanIterator(everyOtherSampler,
spans);
assertThat(result).extracting(s -> s.name).containsExactly("foo", "baz");
assertThat(result).extracting(s -> s.name).containsExactly(
"message:/foo", "message:/baz");
}
Span span(String name) {
Long id = new Random().nextLong();
return new Span(1, 3, name, id, Collections.<Long>emptyList(), id, true, true,
return new Span(1, 3, new SpanName("message", "/" + name), id, Collections.<Long>emptyList(), id, true, true,
"process");
}
}

View File

@@ -17,6 +17,8 @@
package org.springframework.cloud.sleuth.zipkin.stream;
import java.util.Collections;
import org.springframework.cloud.sleuth.SpanName;
import zipkin.BinaryAnnotation;
import zipkin.Endpoint;
@@ -27,7 +29,7 @@ import org.springframework.cloud.sleuth.stream.Host;
import static org.assertj.core.api.Assertions.assertThat;
public class ZipkinMessageListenerTests {
Span span = new Span(1, 3, "name", 1L, Collections.<Long>emptyList(), 2L, true, true,
Span span = new Span(1, 3, new SpanName("http", "name"), 1L, Collections.<Long>emptyList(), 2L, true, true,
"process");
Host host = new Host("myservice", "1.2.3.4", 8080);
Endpoint endpoint = Endpoint.create("myservice", 1 << 24 | 2 << 16 | 3 << 8 | 4, 8080);
@@ -80,7 +82,7 @@ public class ZipkinMessageListenerTests {
// TODO: "unknown" bc process id, documented as not nullable, is null in some tests.
@Test
public void nullProcessIdCoercesToUnknownServiceName() {
Span noProcessId = Span.builder().traceId(1L).name("parent").remote(true).build();
Span noProcessId = Span.builder().traceId(1L).name(new SpanName("http", "parent")).remote(true).build();
zipkin.Span result = SamplingZipkinSpanIterator.convert(noProcessId, this.host);

View File

@@ -19,8 +19,10 @@ package org.springframework.cloud.sleuth.zipkin;
import java.nio.charset.Charset;
import java.util.Map;
import lombok.extern.apachecommons.CommonsLog;
import org.springframework.cloud.sleuth.Log;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.event.ClientReceivedEvent;
import org.springframework.cloud.sleuth.event.ClientSentEvent;
import org.springframework.cloud.sleuth.event.ServerReceivedEvent;
@@ -29,9 +31,6 @@ import org.springframework.cloud.sleuth.event.SpanAcquiredEvent;
import org.springframework.cloud.sleuth.event.SpanReleasedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.util.StringUtils;
import lombok.extern.apachecommons.CommonsLog;
import zipkin.Annotation;
import zipkin.BinaryAnnotation;
import zipkin.Constants;
@@ -150,8 +149,8 @@ public class ZipkinSpanListener {
zipkinSpan.parentId(span.getParents().get(0));
}
zipkinSpan.id(span.getSpanId());
if (StringUtils.hasText(span.getName())) {
zipkinSpan.name(span.getName());
if (!SpanName.NO_NAME.equals(span.getName())) {
zipkinSpan.name(span.getName().toString());
}
return zipkinSpan.build();
}

View File

@@ -16,14 +16,10 @@
package org.springframework.cloud.sleuth.zipkin;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
@@ -31,6 +27,7 @@ import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfigurati
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.cloud.sleuth.Sampler;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration;
import org.springframework.cloud.sleuth.event.ClientReceivedEvent;
@@ -45,6 +42,9 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
/**
* @author Dave Syer
*
@@ -70,7 +70,7 @@ public class ZipkinSpanListenerTests {
this.test.spans.clear();
}
Span parent = Span.builder().traceId(1L).name("parent").remote(true).build();
Span parent = Span.builder().traceId(1L).name(new SpanName("http", "parent")).remote(true).build();
/** Sleuth timestamps are millisecond granularity while zipkin is microsecond. */
@Test
@@ -118,7 +118,7 @@ public class ZipkinSpanListenerTests {
*/
@Test
public void spanWithoutAnnotationsLogsComponent() {
Span context = this.tracer.startTrace("foo");
Span context = this.tracer.startTrace(new SpanName("http", "foo"));
this.tracer.close(context);
assertEquals(1, this.test.spans.size());
assertThat(this.test.spans.get(0).binaryAnnotations.get(0).endpoint.serviceName)
@@ -127,7 +127,7 @@ public class ZipkinSpanListenerTests {
@Test
public void rpcAnnotations() {
Span context = this.tracer.joinTrace("child", this.parent);
Span context = this.tracer.joinTrace(new SpanName("http", "child"), this.parent);
this.application.publishEvent(new ClientSentEvent(this, context));
this.application.publishEvent(new ServerReceivedEvent(this, this.parent, context));
this.application.publishEvent(new ServerSentEvent(this, this.parent, context));