Integrate server-side zipkin with core

This commit is contained in:
Dave Syer
2015-07-28 17:11:18 +01:00
parent 19dfe2b0d6
commit cba63d0dec
32 changed files with 297 additions and 654 deletions

View File

@@ -1,12 +1,16 @@
package org.springframework.cloud.sleuth;
import java.io.Closeable;
import java.util.ArrayList;
import java.util.List;
import lombok.SneakyThrows;
import lombok.Value;
import lombok.experimental.NonFinal;
import lombok.extern.apachecommons.CommonsLog;
import org.springframework.cloud.sleuth.event.SpanStoppedEvent;
import org.springframework.cloud.sleuth.util.ExceptionUtils;
import org.springframework.context.ApplicationEventPublisher;
/**
@@ -14,6 +18,7 @@ import org.springframework.context.ApplicationEventPublisher;
*/
@Value
@NonFinal
@CommonsLog
public class TraceScope implements Closeable {
private final ApplicationEventPublisher publisher;
@@ -28,6 +33,11 @@ public class TraceScope implements Closeable {
*/
private final Span savedSpan;
/**
* List of callbacks to run on close.
*/
private List<Runnable> callbacks = new ArrayList<Runnable>();
@NonFinal
private boolean detached = false;
@@ -45,41 +55,54 @@ public class TraceScope implements Closeable {
* @return the same Span object
*/
public Span detach() {
if (detached) {
Utils.error("Tried to detach trace span " + span + " but " +
if (this.detached) {
ExceptionUtils.error("Tried to detach trace span " + this.span + " but " +
"it has already been detached.");
}
detached = true;
this.detached = true;
Span cur = TraceContextHolder.getCurrentSpan();
if (cur != span) {
Utils.error("Tried to detach trace span " + span + " but " +
if (cur != this.span) {
ExceptionUtils.error("Tried to detach trace span " + this.span + " but " +
"it is not the current span for the " +
Thread.currentThread().getName() + " thread. You have " +
"probably forgotten to close or detach " + cur);
} else {
TraceContextHolder.setCurrentSpan(savedSpan);
TraceContextHolder.setCurrentSpan(this.savedSpan);
}
return this.span;
}
public void register(Runnable callback) {
if (!this.callbacks .contains(callback)) {
this.callbacks.add(callback);
}
return span;
}
@Override
@SneakyThrows
public void close() {
if (detached) {
if (this.detached) {
return;
}
detached = true;
this.detached = true;
for (Runnable callback : this.callbacks) {
try {
callback.run();
} catch (Throwable e) {
log.error("Error with callback on close", e);
}
}
Span cur = TraceContextHolder.getCurrentSpan();
if (cur != span) {
Utils.error("Tried to close trace span " + span + " but " +
if (cur != this.span) {
ExceptionUtils.error("Tried to close trace span " + this.span + " but " +
"it is not the current span for the " +
Thread.currentThread().getName() + " thread. You have " +
"probably forgotten to close or detach " + cur);
} else {
span.stop();
this.publisher.publishEvent(new SpanStoppedEvent(this, span));
TraceContextHolder.setCurrentSpan(savedSpan);
this.span.stop();
this.publisher.publishEvent(new SpanStoppedEvent(this, this.span));
TraceContextHolder.setCurrentSpan(this.savedSpan);
}
}

View File

@@ -1,7 +1,12 @@
package org.springframework.cloud.sleuth;
package org.springframework.cloud.sleuth.autoconfig;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.sleuth.IdGenerator;
import org.springframework.cloud.sleuth.RandomUuidGenerator;
import org.springframework.cloud.sleuth.Sampler;
import org.springframework.cloud.sleuth.Trace;
import org.springframework.cloud.sleuth.sampler.IsTracingSampler;
import org.springframework.cloud.sleuth.trace.DefaultTrace;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -20,13 +25,13 @@ public class TraceAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public Sampler defaultSampler() {
public Sampler<?> defaultSampler() {
return new IsTracingSampler();
}
@Bean
@ConditionalOnMissingBean
public Trace trace(Sampler sampler, IdGenerator idGenerator,
public Trace trace(Sampler<?> sampler, IdGenerator idGenerator,
ApplicationEventPublisher publisher) {
return new DefaultTrace(sampler, idGenerator, publisher);
}

View File

@@ -1,10 +1,10 @@
package org.springframework.cloud.sleuth;
package org.springframework.cloud.sleuth.event;
import java.util.ArrayList;
import lombok.Value;
import org.springframework.cloud.sleuth.event.SpanStoppedEvent;
import org.springframework.cloud.sleuth.Span;
import org.springframework.context.ApplicationListener;
/**

View File

@@ -1,5 +1,6 @@
package org.springframework.cloud.sleuth.instrument;
import lombok.EqualsAndHashCode;
import lombok.Value;
import org.springframework.cloud.sleuth.Span;
@@ -10,6 +11,7 @@ import org.springframework.cloud.sleuth.TraceScope;
* @author Spencer Gibb
*/
@Value
@EqualsAndHashCode(callSuper=false)
public class TraceRunnable extends TraceDelegate<Runnable> implements Runnable {
public TraceRunnable(Trace trace, Runnable delagate) {

View File

@@ -30,6 +30,8 @@ import javax.servlet.http.HttpServletResponse;
import org.springframework.cloud.sleuth.Trace;
import org.springframework.cloud.sleuth.TraceInfo;
import org.springframework.cloud.sleuth.TraceScope;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.web.filter.OncePerRequestFilter;
/**
@@ -44,6 +46,7 @@ import org.springframework.web.filter.OncePerRequestFilter;
* @author Marcin Grzejszczak, 4financeIT
* @author Spencer Gibb
*/
@Order(Ordered.HIGHEST_PRECEDENCE + 5)
public class TraceFilter extends OncePerRequestFilter {
public static final Pattern DEFAULT_SKIP_PATTERN = Pattern
@@ -65,10 +68,10 @@ public class TraceFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
throws ServletException, IOException {
String uri = hasText(request.getRequestURI()) ? request.getRequestURI() : "";
boolean skip = skipPattern.matcher(uri).matches();
boolean skip = this.skipPattern.matcher(uri).matches();
TraceScope traceScope = null;
if (!skip) {
@@ -78,13 +81,13 @@ public class TraceFilter extends OncePerRequestFilter {
TraceInfo traceInfo = new TraceInfo(traceId, spanId);
// TODO: trace description?
traceScope = trace.startSpan("traceFilter", traceInfo);
traceScope = this.trace.startSpan("traceFilter", traceInfo);
// Send new span id back
addToResponseIfNotPresent(response, SPAN_ID_NAME, traceScope.getSpan()
.getSpanId());
}
else {
traceScope = trace.startSpan("traceFilter");
traceScope = this.trace.startSpan("traceFilter");
}
}

View File

@@ -67,12 +67,12 @@ public class TraceWebAspect {
@Around("anyControllerOrRestControllerWithPublicAsyncMethod()")
@SuppressWarnings("unchecked")
public Object wrapWithCorrelationId(ProceedingJoinPoint pjp) throws Throwable {
Callable callable = (Callable) pjp.proceed();
Callable<Object> callable = (Callable<Object>) pjp.proceed();
if (TraceContextHolder.isTracing()) {
log.debug("Wrapping callable with span ["
+ TraceContextHolder.getCurrentSpan() + "]");
return new TraceCallable(this.trace, callable);
return new TraceCallable<Object>(this.trace, callable);
}
else {
return callable;

View File

@@ -27,8 +27,6 @@ import org.springframework.cloud.sleuth.Trace;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* Registers beans that add tracing to requests
@@ -55,41 +53,15 @@ public class TraceWebAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public TraceWebAspect traceWebAspect() {
return new TraceWebAspect(trace);
return new TraceWebAspect(this.trace);
}
//TODO: I don't think TraceHandlerInterceptor is needed with TraceFilter
/*@Bean
@ConditionalOnMissingBean
public TraceHandlerInterceptor traceHandlerInterceptor() {
return new TraceHandlerInterceptor(trace);
}
@Bean
public WebMvcConfigurerAdapter webMvcConfigurerAdapter(
TraceHandlerInterceptor handlerInterceptor) {
return new TraceWebConfigurer(handlerInterceptor);
}
protected static class TraceWebConfigurer extends WebMvcConfigurerAdapter {
private TraceHandlerInterceptor interceptor;
public TraceWebConfigurer(TraceHandlerInterceptor interceptor) {
this.interceptor = interceptor;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(interceptor).addPathPatterns("/**");
}
}*/
@Bean
@ConditionalOnMissingBean
public FilterRegistrationBean traceFilter() {
Pattern pattern = StringUtils.hasText(skipPattern) ? Pattern.compile(skipPattern)
Pattern pattern = StringUtils.hasText(this.skipPattern) ? Pattern.compile(this.skipPattern)
: TraceFilter.DEFAULT_SKIP_PATTERN;
return new FilterRegistrationBean(new TraceFilter(trace, pattern));
return new FilterRegistrationBean(new TraceFilter(this.trace, pattern));
}
}

View File

@@ -1,10 +1,18 @@
package org.springframework.cloud.sleuth;
package org.springframework.cloud.sleuth.trace;
import static org.springframework.cloud.sleuth.Utils.error;
import static org.springframework.cloud.sleuth.util.ExceptionUtils.error;
import java.util.Collections;
import java.util.concurrent.Callable;
import org.springframework.cloud.sleuth.IdGenerator;
import org.springframework.cloud.sleuth.MilliSpan;
import org.springframework.cloud.sleuth.NullScope;
import org.springframework.cloud.sleuth.Sampler;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Trace;
import org.springframework.cloud.sleuth.TraceContextHolder;
import org.springframework.cloud.sleuth.TraceInfo;
import org.springframework.cloud.sleuth.TraceScope;
import org.springframework.cloud.sleuth.event.SpanStartedEvent;
import org.springframework.cloud.sleuth.instrument.TraceCallable;
import org.springframework.cloud.sleuth.instrument.TraceRunnable;
@@ -30,7 +38,7 @@ public class DefaultTrace implements Trace {
@Override
public TraceScope startSpan(String name) {
return this.startSpan(name, defaultSampler);
return this.startSpan(name, this.defaultSampler);
}
@Override
@@ -40,7 +48,7 @@ public class DefaultTrace implements Trace {
.begin(System.currentTimeMillis())
.name(name)
.traceId(tinfo.getTraceId())
.spanId(idGenerator.create())
.spanId(this.idGenerator.create())
.parent(tinfo.getSpanId())
.build();
return doStart(span);
@@ -81,8 +89,8 @@ public class DefaultTrace implements Trace {
return MilliSpan.builder()
.begin(System.currentTimeMillis())
.name(name)
.traceId(idGenerator.create())
.spanId(idGenerator.create())
.traceId(this.idGenerator.create())
.spanId(this.idGenerator.create())
.build();
} else {
return createChild(parent, name);
@@ -95,14 +103,14 @@ public class DefaultTrace implements Trace {
.name(childname)
.traceId(parent.getTraceId())
.parent(parent.getSpanId())
.spanId(idGenerator.create())
.spanId(this.idGenerator.create())
.processId(parent.getProcessId())
.build();
}
protected TraceScope doStart(Span span) {
if (span != null) {
publisher.publishEvent(new SpanStartedEvent(this, span));
this.publisher.publishEvent(new SpanStartedEvent(this, span));
}
return continueSpan(span);
}

View File

@@ -1,4 +1,4 @@
package org.springframework.cloud.sleuth;
package org.springframework.cloud.sleuth.util;
import lombok.extern.apachecommons.CommonsLog;
@@ -6,7 +6,7 @@ import lombok.extern.apachecommons.CommonsLog;
* @author Spencer Gibb
*/
@CommonsLog
public abstract class Utils {
public abstract class ExceptionUtils {
public static void error(String msg) {
log.error(msg);
throw new RuntimeException(msg);

View File

@@ -1,6 +1,6 @@
# Auto Configuration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.sleuth.TraceAutoConfiguration,\
org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration,\
org.springframework.cloud.sleuth.slf4j.SleuthSlf4jAutoConfiguration,\
org.springframework.cloud.sleuth.instrument.web.TraceWebAutoConfiguration,\
org.springframework.cloud.sleuth.instrument.web.client.TraceWebClientAutoConfiguration

View File

@@ -17,6 +17,7 @@ import org.springframework.cloud.sleuth.event.SpanStartedEvent;
import org.springframework.cloud.sleuth.event.SpanStoppedEvent;
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
import org.springframework.cloud.sleuth.sampler.IsTracingSampler;
import org.springframework.cloud.sleuth.trace.DefaultTrace;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;