diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/TraceInfo.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/BasicSpanIdentifiers.java similarity index 75% rename from spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/TraceInfo.java rename to spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/BasicSpanIdentifiers.java index d9dc6035d..0291f063a 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/TraceInfo.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/BasicSpanIdentifiers.java @@ -6,7 +6,7 @@ import lombok.Data; * @author Spencer Gibb */ @Data -public class TraceInfo implements SpanIdentifiers { +public class BasicSpanIdentifiers implements SpanIdentifiers { private final String traceId; private final String spanId; private String processId; diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/TraceScope.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/TraceScope.java index 8c01cf444..b92de4f54 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/TraceScope.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/TraceScope.java @@ -39,26 +39,27 @@ public class TraceScope implements Closeable { } /** - * Remove this span as the current thread, but don't stop it yet or - * send it for collection. This is useful if the span object is then - * passed to another thread for use with Trace.continueTrace(). + * Remove this span as the current thread, but don't stop it yet or send it for + * collection. This is useful if the span object is then passed to another thread for + * use with Trace.continueTrace(). * * @return the same Span object */ public SpanIdentifiers detach() { if (this.detached) { - ExceptionUtils.error("Tried to detach trace span " + this.span + " but " + - "it has already been detached."); + ExceptionUtils.error("Tried to detach trace span " + this.span + " but " + + "it has already been detached."); } this.detached = true; SpanIdentifiers cur = TraceContextHolder.getCurrentSpan(); 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 { + 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(this.savedSpan); } return this.span; @@ -73,13 +74,19 @@ public class TraceScope implements Closeable { this.detached = true; SpanIdentifiers cur = TraceContextHolder.getCurrentSpan(); 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 { + 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 { this.span.stop(); - this.publisher.publishEvent(new SpanStoppedEvent(this, this.span)); + if (this.savedSpan != null && this.span.getParents().contains(this.savedSpan.getSpanId())) { + this.publisher.publishEvent(new SpanStoppedEvent(this, this.savedSpan, this.span)); + } + else { + this.publisher.publishEvent(new SpanStoppedEvent(this, this.span)); + } TraceContextHolder.setCurrentSpan(this.savedSpan); } } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/event/SpanStartedEvent.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/event/SpanStartedEvent.java index 8a0f9314b..676db75b3 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/event/SpanStartedEvent.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/event/SpanStartedEvent.java @@ -1,23 +1,30 @@ package org.springframework.cloud.sleuth.event; +import lombok.Data; import lombok.EqualsAndHashCode; -import lombok.Value; import org.springframework.cloud.sleuth.Span; +import org.springframework.cloud.sleuth.SpanIdentifiers; import org.springframework.context.ApplicationEvent; /** * @author Spencer Gibb */ -@Value +@Data @EqualsAndHashCode(callSuper=false) @SuppressWarnings("serial") public class SpanStartedEvent extends ApplicationEvent { + private final SpanIdentifiers parent; private final Span span; public SpanStartedEvent(Object source, Span span) { + this(source, null, span); + } + + public SpanStartedEvent(Object source, SpanIdentifiers parent, Span span) { super(source); + this.parent = parent; this.span = span; } } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/event/SpanStoppedEvent.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/event/SpanStoppedEvent.java index 1b45c066e..d9ab4c07d 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/event/SpanStoppedEvent.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/event/SpanStoppedEvent.java @@ -1,23 +1,30 @@ package org.springframework.cloud.sleuth.event; +import lombok.Data; import lombok.EqualsAndHashCode; -import lombok.Value; import org.springframework.cloud.sleuth.Span; +import org.springframework.cloud.sleuth.SpanIdentifiers; import org.springframework.context.ApplicationEvent; /** * @author Spencer Gibb */ -@Value +@Data @EqualsAndHashCode(callSuper=false) @SuppressWarnings("serial") public class SpanStoppedEvent extends ApplicationEvent { private final Span span; + private final SpanIdentifiers parent; public SpanStoppedEvent(Object source, Span span) { + this(source, null, span); + } + + public SpanStoppedEvent(Object source, SpanIdentifiers parent, Span span) { super(source); + this.parent = parent; this.span = span; } } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceFilter.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceFilter.java index e4edea0b7..4fd286244 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceFilter.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceFilter.java @@ -27,8 +27,8 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.springframework.cloud.sleuth.BasicSpanIdentifiers; 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; @@ -72,17 +72,17 @@ public class TraceFilter extends OncePerRequestFilter { HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { - String uri = hasText(request.getRequestURI()) ? request.getRequestURI() : ""; + String uri = this.urlPathHelper.getPathWithinApplication(request); boolean skip = this.skipPattern.matcher(uri).matches(); TraceScope traceScope = null; if (!skip) { String spanId = getHeader(request, response, SPAN_ID_NAME); String traceId = getHeader(request, response, TRACE_ID_NAME); - String name = "http" + this.urlPathHelper.getPathWithinApplication(request); + String name = "http" + uri; if (hasText(spanId) && hasText(traceId)) { - TraceInfo traceInfo = new TraceInfo(traceId, spanId); + BasicSpanIdentifiers traceInfo = new BasicSpanIdentifiers(traceId, spanId); // TODO: trace description? traceScope = this.trace.startSpan(name, traceInfo); // Send new span id back diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TracePreFilter.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TracePreFilter.java index f48d377f6..7bd3767f1 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TracePreFilter.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TracePreFilter.java @@ -7,7 +7,7 @@ import static org.springframework.util.StringUtils.hasText; import javax.servlet.http.HttpServletRequest; import org.springframework.cloud.sleuth.Trace; -import org.springframework.cloud.sleuth.TraceInfo; +import org.springframework.cloud.sleuth.BasicSpanIdentifiers; import org.springframework.cloud.sleuth.TraceScope; import com.netflix.zuul.ZuulFilter; @@ -49,7 +49,7 @@ public class TracePreFilter extends ZuulFilter { TraceScope traceScope = null; if (hasText(spanId) && hasText(traceId)) { - TraceInfo traceInfo = new TraceInfo(traceId, spanId); + BasicSpanIdentifiers traceInfo = new BasicSpanIdentifiers(traceId, spanId); // TODO: trace description? traceScope = trace.startSpan("traceZuulFilter", traceInfo); } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/trace/DefaultTrace.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/trace/DefaultTrace.java index df123e24b..9e7775078 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/trace/DefaultTrace.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/trace/DefaultTrace.java @@ -47,7 +47,7 @@ public class DefaultTrace implements Trace { + " tried to start a new Span " + "with parent " + parent.toString() + ", but there is already a " + "currentSpan " + currentSpan); } - return doStart(createChild(parent, name)); + return continueSpan(createChild(parent, name)); } @Override @@ -61,30 +61,27 @@ public class DefaultTrace implements Trace { if (TraceContextHolder.isTracing() || s.next(info)) { span = createChild(getCurrentSpan(), name); } - return doStart(span); + return continueSpan(span); } protected Span createChild(SpanIdentifiers parent, String name) { if (parent == null) { - return MilliSpan.builder().begin(System.currentTimeMillis()).name(name) + MilliSpan span = MilliSpan.builder().begin(System.currentTimeMillis()).name(name) .traceId(this.idGenerator.create()).spanId(this.idGenerator.create()) .build(); + this.publisher.publishEvent(new SpanStartedEvent(this, span)); + return span; } else { - return MilliSpan.builder().begin(System.currentTimeMillis()).name(name) + MilliSpan span = MilliSpan.builder().begin(System.currentTimeMillis()).name(name) .traceId(parent.getTraceId()).parent(parent.getSpanId()) .spanId(this.idGenerator.create()).processId(parent.getProcessId()) .build(); + this.publisher.publishEvent(new SpanStartedEvent(this, parent, span)); + return span; } } - protected TraceScope doStart(Span span) { - if (span != null) { - this.publisher.publishEvent(new SpanStartedEvent(this, span)); - } - return continueSpan(span); - } - @Override public TraceScope continueSpan(Span span) { // Return an empty TraceScope that does nothing on close diff --git a/spring-cloud-sleuth-sample/src/main/java/org/springframework/cloud/sleuth/sample/SampleApplication.java b/spring-cloud-sleuth-sample/src/main/java/org/springframework/cloud/sleuth/sample/SampleApplication.java index bcb833d8f..a9ddce9ca 100644 --- a/spring-cloud-sleuth-sample/src/main/java/org/springframework/cloud/sleuth/sample/SampleApplication.java +++ b/spring-cloud-sleuth-sample/src/main/java/org/springframework/cloud/sleuth/sample/SampleApplication.java @@ -34,6 +34,10 @@ public class SampleApplication { SpringApplication.run(SampleApplication.class, args); } - //@Bean public SpanCollector spanCollector() { return new LoggingSpanCollectorImpl(); } + // Use this for debugging (or if there is no Zipkin collector running on port 9410) + // @Bean + // public SpanCollector spanCollector() { + // return new LoggingSpanCollectorImpl(); + // } } diff --git a/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ZipkinAutoConfiguration.java b/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ZipkinAutoConfiguration.java index 275a0083b..caae6c1a6 100644 --- a/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ZipkinAutoConfiguration.java +++ b/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ZipkinAutoConfiguration.java @@ -41,8 +41,8 @@ import com.google.common.base.Optional; public class ZipkinAutoConfiguration { @Bean - @ConditionalOnMissingBean - public SpanCollector spanCollector() { + @ConditionalOnMissingBean(SpanCollector.class) + public ZipkinSpanCollector spanCollector() { return new ZipkinSpanCollector(zipkinProperties().getHost(), zipkinProperties() .getPort()); } diff --git a/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ZipkinSpanListener.java b/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ZipkinSpanListener.java index 41c9716ca..582d6ae0a 100644 --- a/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ZipkinSpanListener.java +++ b/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ZipkinSpanListener.java @@ -3,8 +3,8 @@ package org.springframework.cloud.sleuth.zipkin; import lombok.Data; import lombok.extern.apachecommons.CommonsLog; -import org.springframework.cloud.sleuth.SpanIdentifiers; import org.springframework.cloud.sleuth.Span; +import org.springframework.cloud.sleuth.SpanIdentifiers; import org.springframework.cloud.sleuth.event.SpanStartedEvent; import org.springframework.cloud.sleuth.event.SpanStoppedEvent; import org.springframework.context.event.EventListener; @@ -25,23 +25,20 @@ public class ZipkinSpanListener { @EventListener public void start(SpanStartedEvent event) { - preTrace(event.getSpan()); + preTrace(event.getParent(), event.getSpan()); } @EventListener - public void start(SpanStoppedEvent event) { - postTrace(event.getSpan()); + public void stop(SpanStoppedEvent event) { + postTrace(event.getParent(), event.getSpan()); } - protected void preTrace(Span context) { - final TraceData traceData = getTraceData(context); - - final String spanName = getSpanName(context, traceData); - if (traceData.getTraceId() != null && traceData.getSpanId() != null) { - + protected void preTrace(SpanIdentifiers parent, Span span) { + String spanName = span.getName(); + if (span.getTraceId() != null && span.getSpanId() != null) { log.debug("Received span information as part of request."); - this.serverTracer.setStateCurrentTrace(traceData.getTraceId(), - traceData.getSpanId(), traceData.getParentSpanId(), spanName); + this.serverTracer.setStateCurrentTrace(hash(span.getTraceId()), + getSpanId(span), getSpanId(parent), spanName); } else { log.debug("Received no span state."); @@ -50,22 +47,15 @@ public class ZipkinSpanListener { this.serverTracer.setServerReceived(); } - protected TraceData getTraceData(Span context) { - TraceData trace = new TraceData(); - trace.setTraceId(hash(context.getTraceId())); - trace.setSpanId(hash(context.getSpanId())); - trace.setSpanName(context.getName()); - if (!context.getParents().isEmpty()) { - trace.setParentSpanId(hash(context.getParents().iterator().next())); - } - return trace; + private Long getSpanId(SpanIdentifiers span) { + return span == null ? null : hash(span.getSpanId()); } protected String getSpanName(Span context, TraceData traceData) { return context.getName(); } - protected void postTrace(SpanIdentifiers context) { + protected void postTrace(SpanIdentifiers parent, Span span) { // We can submit this in any case. When server state is not set or // we should not trace this request nothing will happen. log.debug("Sending server send.");