[#106] Converted UUID to Long

- Changed Random instantiation to a shared Random
- Changed the name of the converter
- Changed generator into random
- Span id is now non-nullable.
    - it gets generated in the http filter if it's not there
    - it's generated in the spring-integration channels if it wasn't set
This commit is contained in:
Marcin Grzejszczak
2016-01-18 14:38:09 +01:00
parent 483737fdc1
commit 82ed9f78a1
68 changed files with 685 additions and 888 deletions

View File

@@ -35,10 +35,10 @@ public class MilliSpan implements Span {
private final long begin;
private long end = 0;
private final String name;
private final String traceId;
private final long traceId;
@Singular
private List<String> parents = new ArrayList<>();
private final String spanId;
private List<Long> parents = new ArrayList<>();
private final long spanId;
private boolean remote = false;
private boolean exportable = true;
private final Map<String, String> tags = new LinkedHashMap<>();
@@ -50,7 +50,7 @@ public class MilliSpan implements Span {
return new MilliSpan().toBuilder();
}
public MilliSpan(long begin, long end, String name, String traceId, List<String> parents, String spanId, boolean remote, boolean exportable, String processId) {
public MilliSpan(long begin, long end, String name, long traceId, List<Long> parents, long spanId, boolean remote, boolean exportable, String processId) {
this.begin = begin<=0 ? System.currentTimeMillis() : begin;
this.end = end;
this.name = name;
@@ -66,9 +66,10 @@ public class MilliSpan implements Span {
private MilliSpan() {
this.begin = 0;
this.name = null;
this.traceId = null;
this.spanId = null;
this.traceId = 0;
this.spanId = 0;
this.processId = null;
this.parents = new ArrayList<>();
}
@Override

View File

@@ -16,6 +16,9 @@
package org.springframework.cloud.sleuth;
import org.springframework.util.Assert;
import java.math.BigInteger;
import java.util.List;
import java.util.Map;
@@ -41,18 +44,18 @@ public interface Span {
* The spanId is immutable and cannot be changed. It is safe to access this from
* multiple threads.
*/
String getSpanId();
long getSpanId();
/**
* A pseudo-unique (random) number assigned to the trace associated with this span
*/
String getTraceId();
long getTraceId();
/**
* Return a unique id for the process from which this Span originated.
* <p/>
* <p/>
* Will never be null.
* // TODO: Check when this is going to be null (cause it may be null)
*/
String getProcessId();
@@ -62,7 +65,7 @@ public interface Span {
* <p/>
* The collection will be empty if there are no parents.
*/
List<String> getParents();
List<Long> getParents();
/**
* Flag that tells us whether the span was started in another process. Useful in RPC
@@ -127,4 +130,26 @@ public interface Span {
* Will never be null.
*/
List<Log> logs();
/**
* Class used for conversions of long ids to their String representation
*/
class IdConverter {
/**
* Represents given long id as hex string
*/
public static String toHex(long id) {
return Long.toHexString(id);
}
/**
* Represents hex string as long
*/
public static long fromHex(String hexString) {
Assert.hasText(hexString, "Can't convert empty hex string to long");
return new BigInteger(hexString, 16).longValue();
}
}
}

View File

@@ -19,15 +19,13 @@ package org.springframework.cloud.sleuth.autoconfig;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.sleuth.Sampler;
import org.springframework.cloud.sleuth.sampler.DefaultStringToUuidConverter;
import org.springframework.cloud.sleuth.sampler.IsTracingSampler;
import org.springframework.cloud.sleuth.sampler.StringToUuidConverter;
import org.springframework.cloud.sleuth.trace.DefaultTraceManager;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.IdGenerator;
import org.springframework.util.JdkIdGenerator;
import java.util.Random;
/**
* @author Spencer Gibb
@@ -37,9 +35,8 @@ import org.springframework.util.JdkIdGenerator;
public class TraceAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public IdGenerator traceIdGenerator() {
return new JdkIdGenerator();
public Random random() {
return new Random();
}
@Bean
@@ -50,14 +47,8 @@ public class TraceAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public StringToUuidConverter stringToUuidConverter() {
return new DefaultStringToUuidConverter();
}
@Bean
@ConditionalOnMissingBean
public DefaultTraceManager traceManager(Sampler<Void> sampler, IdGenerator idGenerator,
public DefaultTraceManager traceManager(Sampler<Void> sampler,
ApplicationEventPublisher publisher) {
return new DefaultTraceManager(sampler, idGenerator, publisher);
return new DefaultTraceManager(sampler, random(), publisher);
}
}

View File

@@ -9,7 +9,8 @@ import org.springframework.integration.context.IntegrationObjectSupport;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.support.ChannelInterceptorAdapter;
import org.springframework.util.StringUtils;
import java.util.Random;
/**
* Abstraction over classes related to channel intercepting
@@ -20,8 +21,11 @@ abstract class AbstractTraceChannelInterceptor extends ChannelInterceptorAdapter
protected final TraceManager traceManager;
protected AbstractTraceChannelInterceptor(TraceManager traceManager) {
protected final Random random;
protected AbstractTraceChannelInterceptor(TraceManager traceManager, Random random) {
this.traceManager = traceManager;
this.random = random;
}
/**
@@ -29,33 +33,42 @@ abstract class AbstractTraceChannelInterceptor extends ChannelInterceptorAdapter
* trace id passed initially.
*/
Span buildSpan(Message<?> message) {
String spanId = getHeader(message, Trace.SPAN_ID_NAME);
String traceId = getHeader(message, Trace.TRACE_ID_NAME);
if (StringUtils.hasText(traceId)) {
MilliSpan.MilliSpanBuilder span = MilliSpan.builder().traceId(traceId).spanId(spanId);
String parentId = getHeader(message, Trace.PARENT_ID_NAME);
if (message.getHeaders().containsKey(Trace.NOT_SAMPLED_NAME)) {
span.exportable(false);
}
String processId = getHeader(message, Trace.PROCESS_ID_NAME);
String spanName = getHeader(message, Trace.SPAN_NAME_NAME);
if (spanName != null) {
span.name(spanName);
}
if (processId != null) {
span.processId(processId);
}
if (parentId != null) {
span.parent(parentId);
}
span.remote(true);
return span.build();
if (!hasHeader(message, Trace.TRACE_ID_NAME) || !hasHeader(message, Trace.SPAN_ID_NAME)) {
return null; // cannot build a span without ids
}
return null;
long spanId = hasHeader(message, Trace.SPAN_ID_NAME) ?
getHeader(message, Trace.SPAN_ID_NAME, Long.class) : random.nextLong();
long traceId = getHeader(message, Trace.TRACE_ID_NAME, Long.class);
MilliSpan.MilliSpanBuilder span = MilliSpan.builder().traceId(traceId).spanId(spanId);
Long parentId = getHeader(message, Trace.PARENT_ID_NAME, Long.class);
if (message.getHeaders().containsKey(Trace.NOT_SAMPLED_NAME)) {
span.exportable(false);
}
String processId = getHeader(message, Trace.PROCESS_ID_NAME);
String spanName = getHeader(message, Trace.SPAN_NAME_NAME);
if (spanName != null) {
span.name(spanName);
}
if (processId != null) {
span.processId(processId);
}
if (parentId != null) {
span.parent(parentId);
}
span.remote(true);
return span.build();
}
String getHeader(Message<?> message, String name) {
return (String) message.getHeaders().get(name);
return getHeader(message, name, String.class);
}
<T> T getHeader(Message<?> message, String name, Class<T> type) {
return message.getHeaders().get(name, type);
}
boolean hasHeader(Message<?> message, String name) {
return message.getHeaders().containsKey(name);
}
String getChannelName(MessageChannel channel) {

View File

@@ -20,6 +20,7 @@ import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Trace;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.Message;
import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.List;
@@ -88,13 +89,20 @@ public class SpanMessageHeaders {
private static void addHeader(Map<String, String> headers, String name,
String value) {
if (value != null) {
if (StringUtils.hasText(value)) {
headers.put(name, value);
}
}
private static String getFirst(List<String> parents) {
return parents == null || parents.isEmpty() ? null : parents.get(0);
private static void addHeader(Map<String, String> headers, String name,
Long value) {
if (value != null) {
addHeader(headers, name, Span.IdConverter.toHex(value));
}
}
private static Long getFirst(List<Long> parents) {
return parents.isEmpty() ? null : parents.get(0);
}
}

View File

@@ -22,6 +22,7 @@ import org.springframework.cloud.sleuth.trace.TraceContextHolder;
import org.springframework.messaging.Message;
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
import org.springframework.messaging.simp.SimpMessageType;
import org.springframework.util.StringUtils;
import java.util.List;
import java.util.Map;
@@ -64,12 +65,12 @@ public class StompMessageBuilder {
setHeaderIfAbsent(Trace.SPAN_ID_NAME, span.getSpanId());
setHeaderIfAbsent(Trace.TRACE_ID_NAME, span.getTraceId());
setHeaderIfAbsent(Trace.SPAN_NAME_NAME, span.getName());
String parentId = getParentId(TraceContextHolder.getCurrentSpan());
Long parentId = getParentId(TraceContextHolder.getCurrentSpan());
if (parentId != null)
setHeaderIfAbsent(Trace.PARENT_ID_NAME, parentId);
String processId = span.getProcessId();
if (processId != null)
if (StringUtils.hasText(processId))
setHeaderIfAbsent(Trace.PROCESS_ID_NAME, processId);
}
return this;
@@ -113,8 +114,8 @@ public class StompMessageBuilder {
}
}
private String getParentId(final Span currentSpan) {
List<String> parents = currentSpan.getParents();
return parents == null || parents.isEmpty() ? null : parents.get(0);
private Long getParentId(final Span currentSpan) {
List<Long> parents = currentSpan.getParents();
return parents.isEmpty() ? null : parents.get(0);
}
}

View File

@@ -23,6 +23,8 @@ import org.springframework.cloud.sleuth.sampler.IsTracingSampler;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import java.util.Random;
/**
* @author Dave Syer
*
@@ -31,8 +33,8 @@ public class TraceChannelInterceptor extends AbstractTraceChannelInterceptor {
private ThreadLocal<Trace> traceHolder = new ThreadLocal<>();
public TraceChannelInterceptor(TraceManager traceManager) {
super(traceManager);
public TraceChannelInterceptor(TraceManager traceManager, Random random) {
super(traceManager, random);
}
@Override

View File

@@ -16,9 +16,6 @@
package org.springframework.cloud.sleuth.instrument.integration;
import java.util.HashMap;
import java.util.Map;
import org.springframework.aop.support.AopUtils;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Trace;
@@ -31,6 +28,10 @@ import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.ChannelInterceptorAdapter;
import org.springframework.messaging.support.ExecutorChannelInterceptor;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.Map;
/**
* The {@link ExecutorChannelInterceptor} implementation responsible for the {@link Span}
@@ -92,8 +93,8 @@ public class TraceContextPropagationChannelInterceptor extends ChannelIntercepto
return postReceive(message, channel);
}
private String getParentId(Span span) {
return span.getParents() != null && !span.getParents().isEmpty()
private Long getParentId(Span span) {
return !span.getParents().isEmpty()
? span.getParents().get(0) : null;
}
@@ -130,12 +131,12 @@ public class TraceContextPropagationChannelInterceptor extends ChannelIntercepto
setHeader(headers, Trace.SPAN_ID_NAME, this.span.getSpanId());
setHeader(headers, Trace.TRACE_ID_NAME, this.span.getTraceId());
setHeader(headers, Trace.SPAN_NAME_NAME, this.span.getName());
String parentId = getParentId(span);
Long parentId = getParentId(span);
if (parentId != null) {
setHeader(headers, Trace.PARENT_ID_NAME, parentId);
}
String processId = this.span.getProcessId();
if (processId != null) {
String processId = span.getProcessId();
if (StringUtils.hasText(processId)) {
setHeader(headers, Trace.PROCESS_ID_NAME, processId);
}
this.messageHeaders = new MessageHeaders(headers);
@@ -146,6 +147,9 @@ public class TraceContextPropagationChannelInterceptor extends ChannelIntercepto
headers.put(name, value);
}
}
public void setHeader(Map<String, Object> headers, String name, long value) {
setHeader(headers, name, Span.IdConverter.toHex(value));
}
@Override
public Object getPayload() {

View File

@@ -26,6 +26,8 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.config.GlobalChannelInterceptor;
import java.util.Random;
/**
* @author Spencer Gibb
*/
@@ -45,13 +47,13 @@ public class TraceSpringIntegrationAutoConfiguration {
@Bean
@GlobalChannelInterceptor
public TraceChannelInterceptor traceChannelInterceptor(TraceManager traceManager) {
return new TraceChannelInterceptor(traceManager);
public TraceChannelInterceptor traceChannelInterceptor(TraceManager traceManager, Random random) {
return new TraceChannelInterceptor(traceManager, random);
}
@Bean
public TraceStompMessageChannelInterceptor traceStompMessageChannelInterceptor(TraceManager traceManager) {
return new TraceStompMessageChannelInterceptor(traceManager);
public TraceStompMessageChannelInterceptor traceStompMessageChannelInterceptor(TraceManager traceManager, Random random) {
return new TraceStompMessageChannelInterceptor(traceManager, random);
}
@Bean

View File

@@ -22,6 +22,8 @@ import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.support.ChannelInterceptor;
import java.util.Random;
/**
* Interceptor for Stomp Messages sent over websocket
*
@@ -32,8 +34,8 @@ import org.springframework.messaging.support.ChannelInterceptor;
public class TraceStompMessageChannelInterceptor extends AbstractTraceChannelInterceptor implements ChannelInterceptor {
private ThreadLocal<Trace> traceScopeHolder = new ThreadLocal<Trace>();
public TraceStompMessageChannelInterceptor(final TraceManager traceManager) {
super(traceManager);
public TraceStompMessageChannelInterceptor(TraceManager traceManager, Random random) {
super(traceManager, random);
}
@Override

View File

@@ -19,6 +19,7 @@ import static org.springframework.util.StringUtils.hasText;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Random;
import java.util.regex.Pattern;
import javax.servlet.FilterChain;
@@ -40,6 +41,7 @@ import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.UrlPathHelper;
@@ -68,18 +70,22 @@ public class TraceFilter extends OncePerRequestFilter
private final TraceManager traceManager;
private final Pattern skipPattern;
private UrlPathHelper urlPathHelper = new UrlPathHelper();
private final Random random;
private UrlPathHelper urlPathHelper = new UrlPathHelper();
private ApplicationEventPublisher publisher;
public TraceFilter(TraceManager traceManager) {
this.traceManager = traceManager;
this.skipPattern = DEFAULT_SKIP_PATTERN;
this.random = new Random();
}
public TraceFilter(TraceManager traceManager, Pattern skipPattern) {
public TraceFilter(TraceManager traceManager, Pattern skipPattern, Random random) {
this.traceManager = traceManager;
this.skipPattern = skipPattern;
this.random = random;
}
@Override
@@ -105,28 +111,28 @@ public class TraceFilter extends OncePerRequestFilter
addToResponseIfNotPresent(response, Trace.NOT_SAMPLED_NAME, "");
}
String spanId = getHeader(request, response, Trace.SPAN_ID_NAME);
String traceId = getHeader(request, response, Trace.TRACE_ID_NAME);
String name = "http" + uri;
if (hasText(traceId)) {
if (hasHeader(request, response, Trace.TRACE_ID_NAME)) {
long traceId = Span.IdConverter.fromHex(getHeader(request, response, Trace.TRACE_ID_NAME));
long spanId = hasHeader(request, response, Trace.SPAN_ID_NAME) ?
Span.IdConverter.fromHex(getHeader(request, response, Trace.SPAN_ID_NAME)) : random.nextLong();
MilliSpanBuilder span = MilliSpan.builder().traceId(traceId).spanId(spanId);
if (skip) {
span.exportable(false);
}
String parentId = getHeader(request, response, Trace.PARENT_ID_NAME);
String processId = getHeader(request, response, Trace.PROCESS_ID_NAME);
String parentName = getHeader(request, response, Trace.SPAN_NAME_NAME);
if (parentName != null) {
if (StringUtils.hasText(parentName)) {
span.name(parentName);
} else {
span.name("parent/" + name);
}
if (processId != null) {
if (StringUtils.hasText(processId)) {
span.processId(processId);
}
if (parentId != null) {
span.parent(parentId);
if (hasHeader(request, response, Trace.PARENT_ID_NAME)) {
span.parent(Span.IdConverter.fromHex(getHeader(request, response, Trace.PARENT_ID_NAME)));
}
span.remote(true);
@@ -181,8 +187,8 @@ public class TraceFilter extends OncePerRequestFilter
private void addResponseHeaders(HttpServletResponse response, Span span) {
if (span != null) {
response.addHeader(Trace.SPAN_ID_NAME, span.getSpanId());
response.addHeader(Trace.TRACE_ID_NAME, span.getTraceId());
response.addHeader(Trace.SPAN_ID_NAME, Span.IdConverter.toHex(span.getSpanId()));
response.addHeader(Trace.TRACE_ID_NAME, Span.IdConverter.toHex(span.getTraceId()));
}
}
@@ -233,6 +239,12 @@ public class TraceFilter extends OncePerRequestFilter
}
}
private boolean hasHeader(HttpServletRequest request, HttpServletResponse response,
String name) {
String value = request.getHeader(name);
return value != null || response.getHeader(name) != null;
}
private String getHeader(HttpServletRequest request, HttpServletResponse response,
String name) {
String value = request.getHeader(name);

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.cloud.sleuth.instrument.web;
import java.util.Random;
import java.util.regex.Pattern;
import org.springframework.beans.factory.annotation.Autowired;
@@ -65,10 +66,10 @@ public class TraceWebAutoConfiguration {
}
@Bean
public FilterRegistrationBean traceWebFilter(ApplicationEventPublisher publisher) {
public FilterRegistrationBean traceWebFilter(ApplicationEventPublisher publisher, Random random) {
Pattern pattern = StringUtils.hasText(this.skipPattern) ? Pattern.compile(this.skipPattern)
: TraceFilter.DEFAULT_SKIP_PATTERN;
TraceFilter filter = new TraceFilter(this.traceManager, pattern);
TraceFilter filter = new TraceFilter(this.traceManager, pattern, random);
filter.setApplicationEventPublisher(publisher);
return new FilterRegistrationBean(filter);
}

View File

@@ -16,14 +16,10 @@
package org.springframework.cloud.sleuth.instrument.web.client;
import static java.util.Collections.singletonList;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import com.netflix.hystrix.HystrixCommand;
import feign.*;
import feign.codec.Decoder;
import feign.hystrix.HystrixFeign;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
@@ -49,17 +45,15 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Scope;
import org.springframework.util.StringUtils;
import com.netflix.hystrix.HystrixCommand;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import feign.Client;
import feign.Feign;
import feign.FeignException;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import feign.Response;
import feign.codec.Decoder;
import feign.hystrix.HystrixFeign;
import static java.util.Collections.singletonList;
/**
*
@@ -125,12 +119,7 @@ public class TraceFeignClientAutoConfiguration {
setHeader(template, Trace.NOT_SAMPLED_NAME, "");
return;
}
if (span.getSpanId() == null) {
setHeader(template, Trace.TRACE_ID_NAME, span.getTraceId());
setHeader(template, Trace.NOT_SAMPLED_NAME, "");
return;
}
template.header(Trace.TRACE_ID_NAME, span.getTraceId());
template.header(Trace.TRACE_ID_NAME, Span.IdConverter.toHex(span.getTraceId()));
setHeader(template, Trace.SPAN_NAME_NAME, span.getName());
setHeader(template, Trace.SPAN_ID_NAME, span.getSpanId());
setHeader(template, Trace.PARENT_ID_NAME, getParentId(span));
@@ -146,8 +135,8 @@ public class TraceFeignClientAutoConfiguration {
}
}
private String getParentId(Span span) {
return span.getParents() != null && !span.getParents().isEmpty()
private Long getParentId(Span span) {
return !span.getParents().isEmpty()
? span.getParents().get(0) : null;
}
@@ -158,6 +147,12 @@ public class TraceFeignClientAutoConfiguration {
}
}
public void setHeader(RequestTemplate request, String name, Long value) {
if (value != null) {
setHeader(request, name, Span.IdConverter.toHex(value));
}
}
private Map<String, Collection<String>> headersWithTraceId(
Map<String, Collection<String>> headers) {
Map<String, Collection<String>> newHeaders = new HashMap<>();
@@ -167,11 +162,6 @@ public class TraceFeignClientAutoConfiguration {
setHeader(newHeaders, Trace.NOT_SAMPLED_NAME, "");
return newHeaders;
}
if (span.getSpanId() == null) {
setHeader(newHeaders, Trace.TRACE_ID_NAME, span.getTraceId());
setHeader(newHeaders, Trace.NOT_SAMPLED_NAME, "");
return newHeaders;
}
setHeader(newHeaders, Trace.TRACE_ID_NAME, span.getTraceId());
setHeader(newHeaders, Trace.SPAN_ID_NAME, span.getSpanId());
setHeader(newHeaders, Trace.PARENT_ID_NAME, getParentId(span));
@@ -180,10 +170,16 @@ public class TraceFeignClientAutoConfiguration {
public void setHeader(Map<String, Collection<String>> headers, String name,
String value) {
if (value != null && !headers.containsKey(name) && this.accessor.isTracing()) {
if (StringUtils.hasText(value) && !headers.containsKey(name) && this.accessor.isTracing()) {
headers.put(name, singletonList(value));
}
}
public void setHeader(Map<String, Collection<String>> headers, String name,
Long value) {
if (value != null ){
setHeader(headers, name, Span.IdConverter.toHex(value));
}
}
private Span getCurrentSpan() {
return this.accessor.getCurrentSpan();

View File

@@ -15,8 +15,6 @@
*/
package org.springframework.cloud.sleuth.instrument.web.client;
import java.io.IOException;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Trace;
import org.springframework.cloud.sleuth.TraceAccessor;
@@ -29,6 +27,9 @@ 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;
import java.io.IOException;
/**
* Interceptor that verifies whether the trance and span id has been set on the request
@@ -64,11 +65,6 @@ ApplicationEventPublisherAware {
setHeader(request, Trace.NOT_SAMPLED_NAME, "");
return execution.execute(request, body);
}
if (span.getSpanId()==null) {
setHeader(request, Trace.TRACE_ID_NAME, span.getTraceId());
setHeader(request, Trace.NOT_SAMPLED_NAME, "");
return execution.execute(request, body);
}
setHeader(request, Trace.TRACE_ID_NAME, span.getTraceId());
setHeader(request, Trace.SPAN_ID_NAME, span.getSpanId());
setHeader(request, Trace.SPAN_NAME_NAME, span.getName());
@@ -91,17 +87,23 @@ ApplicationEventPublisherAware {
}
}
private String getParentId(Span span) {
return span.getParents() != null && !span.getParents().isEmpty() ? span
private Long getParentId(Span span) {
return !span.getParents().isEmpty() ? span
.getParents().get(0) : null;
}
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);
}
}
public void setHeader(HttpRequest request, String name, Long value) {
if (value != null) {
setHeader(request, name, Span.IdConverter.toHex(value));
}
}
private Span getCurrentSpan() {
return this.accessor.getCurrentSpan();
}

View File

@@ -16,8 +16,8 @@
package org.springframework.cloud.sleuth.instrument.zuul;
import java.util.Map;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Trace;
import org.springframework.cloud.sleuth.TraceAccessor;
@@ -27,8 +27,7 @@ import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.util.ReflectionUtils;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import java.util.Map;
/**
* @author Dave Syer
@@ -65,11 +64,6 @@ ApplicationEventPublisherAware {
setHeader(response, Trace.NOT_SAMPLED_NAME, "");
return null;
}
if (span.getSpanId()==null) {
setHeader(response, Trace.TRACE_ID_NAME, span.getTraceId());
setHeader(response, Trace.NOT_SAMPLED_NAME, "");
return null;
}
try {
setHeader(response, Trace.SPAN_ID_NAME, span.getSpanId());
setHeader(response, Trace.TRACE_ID_NAME, span.getTraceId());
@@ -89,8 +83,8 @@ ApplicationEventPublisherAware {
return this.accessor.getCurrentSpan();
}
private String getParentId(Span span) {
return span.getParents() != null && !span.getParents().isEmpty() ? span
private Long getParentId(Span span) {
return !span.getParents().isEmpty() ? span
.getParents().get(0) : null;
}
@@ -99,6 +93,9 @@ ApplicationEventPublisherAware {
request.put(name, value);
}
}
public void setHeader(Map<String, String> request, String name, Long value) {
setHeader(request, name, Span.IdConverter.toHex(value));
}
@Override
public String filterType() {

View File

@@ -16,9 +16,9 @@
package org.springframework.cloud.sleuth.instrument.zuul;
import java.io.InputStream;
import java.net.URISyntaxException;
import com.netflix.client.http.HttpRequest;
import com.netflix.niws.client.http.RestClient;
import lombok.SneakyThrows;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.cloud.netflix.zuul.filters.route.RestClientRibbonCommand;
import org.springframework.cloud.netflix.zuul.filters.route.RestClientRibbonCommandFactory;
@@ -32,10 +32,8 @@ import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.util.MultiValueMap;
import com.netflix.client.http.HttpRequest;
import com.netflix.niws.client.http.RestClient;
import lombok.SneakyThrows;
import java.io.InputStream;
import java.net.URISyntaxException;
/**
* @author Spencer Gibb
@@ -96,12 +94,6 @@ public class TraceRestClientRibbonCommandFactory extends RestClientRibbonCommand
setHeader(requestBuilder, Trace.NOT_SAMPLED_NAME, "");
return;
}
if (span.getSpanId()==null) {
setHeader(requestBuilder, Trace.TRACE_ID_NAME, span.getTraceId());
setHeader(requestBuilder, Trace.NOT_SAMPLED_NAME, "");
return;
}
setHeader(requestBuilder, Trace.TRACE_ID_NAME, span.getTraceId());
setHeader(requestBuilder, Trace.SPAN_ID_NAME, span.getSpanId());
setHeader(requestBuilder, Trace.SPAN_NAME_NAME, span.getName());
@@ -118,8 +110,8 @@ public class TraceRestClientRibbonCommandFactory extends RestClientRibbonCommand
}
}
private String getParentId(Span span) {
return span.getParents() != null && !span.getParents().isEmpty()
private Long getParentId(Span span) {
return !span.getParents().isEmpty()
? span.getParents().get(0) : null;
}
@@ -129,6 +121,10 @@ public class TraceRestClientRibbonCommandFactory extends RestClientRibbonCommand
}
}
public void setHeader(HttpRequest.Builder builder, String name, Long value) {
setHeader(builder, name, Span.IdConverter.toHex(value));
}
private Span getCurrentSpan() {
return this.accessor.getCurrentSpan();
}

View File

@@ -38,9 +38,9 @@ public class Slf4jSpanListener {
@Order(Ordered.LOWEST_PRECEDENCE)
public void start(SpanAcquiredEvent event) {
Span span = event.getSpan();
MDC.put(Trace.SPAN_ID_NAME, span.getSpanId());
MDC.put(Trace.SPAN_ID_NAME, Span.IdConverter.toHex(span.getSpanId()));
MDC.put(Trace.SPAN_EXPORT_NAME, String.valueOf(span.isExportable()));
MDC.put(Trace.TRACE_ID_NAME, span.getTraceId());
MDC.put(Trace.TRACE_ID_NAME, Span.IdConverter.toHex(span.getTraceId()));
log.trace("Starting span: {}", span);
if (event.getParent() != null) {
log.trace("With parent: {}", event.getParent());
@@ -51,8 +51,8 @@ public class Slf4jSpanListener {
@Order(Ordered.LOWEST_PRECEDENCE)
public void continued(SpanContinuedEvent event) {
Span span = event.getSpan();
MDC.put(Trace.SPAN_ID_NAME, span.getSpanId());
MDC.put(Trace.TRACE_ID_NAME, span.getTraceId());
MDC.put(Trace.SPAN_ID_NAME, Span.IdConverter.toHex(span.getSpanId()));
MDC.put(Trace.TRACE_ID_NAME, Span.IdConverter.toHex(span.getTraceId()));
MDC.put(Trace.SPAN_EXPORT_NAME, String.valueOf(span.isExportable()));
log.trace("Continued span: {}", event.getSpan());
}
@@ -63,7 +63,7 @@ public class Slf4jSpanListener {
log.trace("Stopped span: {}", event.getSpan());
if (event.getParent() != null) {
log.trace("With parent: {}", event.getParent());
MDC.put(Trace.SPAN_ID_NAME, event.getParent().getSpanId());
MDC.put(Trace.SPAN_ID_NAME, Span.IdConverter.toHex(event.getParent().getSpanId()));
MDC.put(Trace.SPAN_EXPORT_NAME, String.valueOf(event.getParent().isExportable()));
}
else {

View File

@@ -1,44 +0,0 @@
package org.springframework.cloud.sleuth.sampler;
import lombok.extern.slf4j.Slf4j;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicLong;
/**
* Default implementation that converts String into UUID
* On parse exceptions a null is returned.
*
* @author Marcin Grzejszczak
* @author Adrian Cole
*/
@Slf4j
public class DefaultStringToUuidConverter implements StringToUuidConverter {
/** Returns a UUID parsed from the input, or null if failed for any reason. */
@Override
public UUID convert(String source) {
try {
UUID uuid = UUID.fromString(source);
incrementSuccess();
return uuid;
} catch (IllegalArgumentException e) {
log.debug("Exception occurred while trying to parse String to UUID", e);
incrementFailures();
return null;
}
}
/**
* Override to increment your counter.
*/
protected void incrementSuccess() {
}
/**
* Override to increment your counter.
*/
protected void incrementFailures() {
}
}

View File

@@ -26,22 +26,22 @@ public class PercentageBasedSampler implements Sampler<Void> {
private final SamplerConfiguration configuration;
private final TraceAccessor traceAccessor;
private final StringToUuidConverter converter;
public PercentageBasedSampler(SamplerConfiguration configuration, TraceAccessor traceAccessor, StringToUuidConverter converter) {
public PercentageBasedSampler(SamplerConfiguration configuration, TraceAccessor traceAccessor) {
this.configuration = configuration;
this.traceAccessor = traceAccessor;
this.converter = converter;
}
@Override
public boolean next(Void info) {
Span currentSpan = traceAccessor.getCurrentSpan();
if (currentSpan == null) {
long threshold = Math.abs(Long.MAX_VALUE * (int) (configuration.getPercentage() * 100)); // drops fractional percentage.
if (currentSpan == null || threshold == 0L) {
return false;
}
return new UuidTraceIdToThresholdComparable(configuration.getPercentage(), converter)
.compareTo(currentSpan.getTraceId()) <= 0;
long traceId = currentSpan.getTraceId();
Long mod = Math.abs(traceId % 100);
return mod.compareTo(threshold) <= 0;
}
}

View File

@@ -1,68 +0,0 @@
package org.springframework.cloud.sleuth.sampler;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.UUID;
/**
* Given the absolute value of a random 128 bit trace id, we expect inputs to be balanced across
* 0-MAX. Threshold is the range of inputs between 0-MAX that we retain.
*
* This decodes a trace id in UUID format into a 128 bit number, then compares it against a threshold.
*
* @author Marcin Grzejszczak
* @author Adrian Cole
*/
final class UuidTraceIdToThresholdComparable implements Comparable<String> {
private static final int SIXTY_FOUR_BITS = 64;
private static final int GREATER_THAN_THRESHOLD = 1;
/**
* 0111....1111 ('0' - for the sign and then 127 times '1')
*/
static final BigInteger MAX_128 = max_128signed();
private final BigInteger threshold;
private final StringToUuidConverter stringToUuidConverter;
UuidTraceIdToThresholdComparable(float rate, StringToUuidConverter converter) {
threshold = MAX_128
.multiply(BigInteger.valueOf((int) (rate * 100))) // drops fractional percentage.
.divide(BigInteger.valueOf(100));
stringToUuidConverter = converter;
}
UuidTraceIdToThresholdComparable(float rate) {
this(rate, new DefaultStringToUuidConverter());
}
/**
* Compares the given Trace Id to the provided threshold
* @param traceId - the UUID version of Trace Id
*/
@Override
public int compareTo(String traceId) {
UUID uuid = stringToUuidConverter.convert(traceId);
if (uuid == null) {
return GREATER_THAN_THRESHOLD;
}
BigInteger asInteger = BigInteger.valueOf(uuid.getMostSignificantBits())
.shiftLeft(SIXTY_FOUR_BITS)
.add(BigInteger.valueOf(uuid.getLeastSignificantBits()))
.abs();
return asInteger.compareTo(threshold);
}
/**
* The Long.MAX_VALUE in binary 0 followed by 63 1s.
*
* We simulate a 128bit long, by doing the same, except following by 127 1s
*/
static BigInteger max_128signed() {
byte[] max_128signed = new byte[16];
Arrays.fill(max_128signed, (byte) -1); // initialize to 11111111
max_128signed[0] = (byte) 127; // reset MSBs to 01111111
return new BigInteger(max_128signed);
}
}

View File

@@ -18,6 +18,7 @@ package org.springframework.cloud.sleuth.trace;
import static org.springframework.cloud.sleuth.util.ExceptionUtils.warn;
import java.util.Random;
import java.util.concurrent.Callable;
import org.springframework.cloud.sleuth.MilliSpan;
@@ -32,7 +33,6 @@ import org.springframework.cloud.sleuth.instrument.TraceCallable;
import org.springframework.cloud.sleuth.instrument.TraceRunnable;
import org.springframework.cloud.sleuth.util.ExceptionUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.util.IdGenerator;
/**
* @author Spencer Gibb
@@ -41,14 +41,14 @@ public class DefaultTraceManager implements TraceManager {
private final Sampler<Void> defaultSampler;
private final IdGenerator idGenerator;
private final ApplicationEventPublisher publisher;
public DefaultTraceManager(Sampler<Void> defaultSampler, IdGenerator idGenerator,
ApplicationEventPublisher publisher) {
private final Random random;
public DefaultTraceManager(Sampler<Void> defaultSampler,
Random random, ApplicationEventPublisher publisher) {
this.defaultSampler = defaultSampler;
this.idGenerator = idGenerator;
this.random = random;
this.publisher = publisher;
}
@@ -79,7 +79,7 @@ public class DefaultTraceManager implements TraceManager {
}
else {
// Non-exportable so we keep the trace but not other data
String id = createId();
long id = createId();
span = MilliSpan.builder().begin(System.currentTimeMillis()).name(name)
.traceId(id).spanId(id).exportable(false).build();
this.publisher.publishEvent(new SpanAcquiredEvent(this, span));
@@ -149,7 +149,7 @@ public class DefaultTraceManager implements TraceManager {
}
protected Span createChild(Span parent, String name) {
String id = createId();
long id = createId();
if (parent == null) {
MilliSpan span = MilliSpan.builder().begin(System.currentTimeMillis())
.name(name).traceId(id).spanId(id).build();
@@ -169,8 +169,8 @@ public class DefaultTraceManager implements TraceManager {
}
}
private String createId() {
return this.idGenerator.generateId().toString();
private long createId() {
return random.nextLong();
}
@Override