From 145cc641c20d0c0abd3520fcf2ec0e3d57610c67 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Wed, 29 Jul 2015 10:37:44 +0100 Subject: [PATCH 1/3] Simplfy some of the core API interfaces and add javadocs --- .../cloud/sleuth/MilliSpan.java | 28 +++---- .../cloud/sleuth/NullScope.java | 2 +- .../springframework/cloud/sleuth/Span.java | 23 +----- .../cloud/sleuth/SpanIdentifiers.java | 46 +++++++++++ .../springframework/cloud/sleuth/Trace.java | 72 ++++++++--------- .../cloud/sleuth/TraceInfo.java | 3 +- .../cloud/sleuth/TraceScope.java | 8 +- .../autoconfig/TraceAutoConfiguration.java | 4 +- .../sleuth/instrument/TraceCallable.java | 18 +++-- .../sleuth/instrument/TraceDelegate.java | 29 +++---- .../sleuth/instrument/TraceRunnable.java | 12 +-- .../sleuth/instrument/web/TraceFilter.java | 2 +- .../cloud/sleuth/sampler/AlwaysSampler.java | 4 +- .../sleuth/sampler/IsTracingSampler.java | 4 +- .../slf4j/Slf4jSpanStartedListener.java | 4 +- .../cloud/sleuth/trace/DefaultTrace.java | 78 ++++++------------- .../cloud/sleuth/DefaultTraceTests.java | 12 +-- .../sleuth/sample/SampleApplication.java | 2 - .../cloud/sleuth/sample/SampleController.java | 6 +- .../cloud/sleuth/zipkin/SleuthTracer.java | 41 +++++----- .../sleuth/zipkin/ZipkinSpanListener.java | 3 +- 21 files changed, 202 insertions(+), 199 deletions(-) create mode 100644 spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/SpanIdentifiers.java diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/MilliSpan.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/MilliSpan.java index 3a361e350..6fc00253f 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/MilliSpan.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/MilliSpan.java @@ -20,50 +20,50 @@ public class MilliSpan implements Span { @NonFinal private long end = 0; private String name; - private String traceId; + private final String traceId; @Singular private List parents; - private String spanId; + private final String spanId; private Map kVAnnotations = new LinkedHashMap<>(); - private String processId; + private final String processId; @Singular private List timelineAnnotations = new ArrayList<>(); @Override public synchronized void stop() { - if (end == 0) { - if (begin == 0) { - throw new IllegalStateException("Span for " + name + if (this.end == 0) { + if (this.begin == 0) { + throw new IllegalStateException("Span for " + this.name + " has not been started"); } - end = System.currentTimeMillis(); + this.end = System.currentTimeMillis(); } } @Override public synchronized long getAccumulatedMillis() { - if (begin == 0) { + if (this.begin == 0) { return 0; } - if (end > 0) { - return end - begin; + if (this.end > 0) { + return this.end - this.begin; } - return System.currentTimeMillis() - begin; + return System.currentTimeMillis() - this.begin; } @Override public synchronized boolean isRunning() { - return begin != 0 && end == 0; + return this.begin != 0 && this.end == 0; } @Override public void addKVAnnotation(String key, String value) { - kVAnnotations.put(key, value); + this.kVAnnotations.put(key, value); } @Override public void addTimelineAnnotation(String msg) { - timelineAnnotations.add(new TimelineAnnotation(System.currentTimeMillis(), msg)); + this.timelineAnnotations.add(new TimelineAnnotation(System.currentTimeMillis(), msg)); } } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/NullScope.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/NullScope.java index 82bad3bcf..72f849a94 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/NullScope.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/NullScope.java @@ -15,7 +15,7 @@ public final class NullScope extends TraceScope { } @Override - public Span detach() { + public SpanIdentifiers detach() { return null; } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Span.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Span.java index 14117f572..7fbad8562 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Span.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Span.java @@ -11,7 +11,7 @@ import java.util.Map; * to keep following the parents of a span until you arrive at a span with no * parents.

*/ -public interface Span { +public interface Span extends SpanIdentifiers { /** * The block has completed, stop the clock */ @@ -45,20 +45,6 @@ public interface Span { */ String getName(); - /** - * A pseudo-unique (random) number assigned to this span instance.

- *

- * The spanId is immutable and cannot be changed. It is safe to access this - * from multiple threads. - */ - String getSpanId(); - - /** - * A pseudo-unique (random) number assigned to the trace associated with this - * span - */ - String getTraceId(); - /** * Returns the parent IDs of the span.

*

@@ -89,11 +75,4 @@ public interface Span { * Will never be null. */ List getTimelineAnnotations(); - - /** - * Return a unique id for the process from which this Span originated.

- *

- * Will never be null. - */ - String getProcessId(); } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/SpanIdentifiers.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/SpanIdentifiers.java new file mode 100644 index 000000000..ae82491a3 --- /dev/null +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/SpanIdentifiers.java @@ -0,0 +1,46 @@ +/* + * Copyright 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; + +/** + * @author Dave Syer + * + */ +public interface SpanIdentifiers { + + /** + * A pseudo-unique (random) number assigned to this span instance.

+ *

+ * The spanId is immutable and cannot be changed. It is safe to access this + * from multiple threads. + */ + String getSpanId(); + + /** + * A pseudo-unique (random) number assigned to the trace associated with this + * span + */ + String getTraceId(); + + /** + * Return a unique id for the process from which this Span originated.

+ *

+ * Will never be null. + */ + String getProcessId(); + +} \ No newline at end of file diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Trace.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Trace.java index 6c9f04116..5f682b201 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Trace.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Trace.java @@ -3,36 +3,34 @@ package org.springframework.cloud.sleuth; import java.util.concurrent.Callable; /** - * The Trace class is the primary way to interact with the library. It provides - * methods to create and manipulate spans. + * The Trace class is the primary way to interact with the library. It provides methods to + * create and manipulate spans. * - * A 'Span' represents a length of time. It has many other attributes such as a - * name, ID, and even potentially a set of key/value strings attached to - * it. + * A 'Span' represents a length of time. It has many other attributes such as a name, ID, + * and even potentially a set of key/value strings attached to it. * - * Each thread in your application has a single currently active currentSpan - * associated with it. When this is non-null, it represents the current - * operation that the thread is doing. Spans are NOT thread-safe, and must - * never be used by multiple threads at once. With care, it is possible to - * safely pass a Span object between threads, but in most cases this is not - * necessary. + * Each thread in your application has a single currently active currentSpan associated + * with it. When this is non-null, it represents the current operation that the thread is + * doing. Spans are NOT thread-safe, and must never be used by multiple threads at once. + * With care, it is possible to safely pass a Span object between threads, but in most + * cases this is not necessary. * - * A 'TraceScope' can either be empty, or contain a Span. TraceScope objects - * implement the Java's Closeable interface. Similar to file descriptors, they - * must be closed after they are created. When a TraceScope contains a Span, - * this span is closed when the scope is closed. + * A 'TraceScope' can either be empty, or contain a Span. TraceScope objects implement the + * Java's Closeable interface. Similar to file descriptors, they must be closed after they + * are created. When a TraceScope contains a Span, this span is closed when the scope is + * closed. * * The 'startSpan' methods in this class do a few things: *

    - *
  • Create a new Span which has this thread's currentSpan as one of its parents.
  • - *
  • Set currentSpan to the new Span.
  • - *
  • Create a TraceSpan object to manage the new Span.
  • + *
  • Create a new Span which has this thread's currentSpan as one of its parents.
  • + *
  • Set currentSpan to the new Span.
  • + *
  • Create a TraceSpan object to manage the new Span.
  • *
* * Closing a TraceScope does a few things: *
    - *
  • It closes the span which the scope was managing.
  • - *
  • Set currentSpan to the previous currentSpan (which may be null).
  • + *
  • It closes the span which the scope was managing.
  • + *
  • Set currentSpan to the previous currentSpan (which may be null).
  • *
*/ public interface Trace { @@ -41,33 +39,37 @@ public interface Trace { String TRACE_ID_NAME = "Trace-Id"; /** - * Creates a new trace scope. + * Creates a trace scope wrapping a new span. *

- * If this thread has a currently active trace span, the trace scope we create - * here will contain a new span descending from the currently active span. - * If there is no currently active trace span, the trace scope we create will - * be empty. + * If this thread has a currently active span, it will be the parent of the span we + * create here, and the trace scope will contain the new span and the parent. If there + * is no currently active trace span, the trace scope we create will be empty. * * @param name The name field for the new span to create. */ TraceScope startSpan(String name); - TraceScope startSpan(String name, TraceInfo tinfo); - /** - * Creates a new trace scope. + * Creates a new trace scope with a specific parent. The parent might be in another + * process or thread. *

- * If this thread has a currently active trace span, it must be the 'parent' - * span that you pass in here as a parameter. The trace scope we create here - * will contain a new span which is a child of 'parent'. + * If this thread has a currently active trace span, it must be the 'parent' span that + * you pass in here as a parameter. The trace scope we create here will contain a new + * span which is a child of 'parent'. * * @param name The name field for the new span to create. */ - TraceScope startSpan(String name, Span parent); + TraceScope startSpan(String name, SpanIdentifiers parent); - TraceScope startSpan(String name, Sampler s); - - TraceScope startSpan(String name, Sampler s, T info); + /** + * Start a new span if the sampler allows it or if we are already tracing in this + * thread. A sampler can be used to limit the number of traces created. + * + * @param name the name of the span + * @param sampler a sampler to decide whether to create the span or not + * @param info the samplers context information + */ + TraceScope startSpan(String name, Sampler sampler, T info); /** * Pick up an existing span from another thread. 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/TraceInfo.java index 5f8485eab..d9dc6035d 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/TraceInfo.java @@ -6,7 +6,8 @@ import lombok.Data; * @author Spencer Gibb */ @Data -public class TraceInfo { +public class TraceInfo 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 61374d30c..8c01cf444 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 @@ -5,7 +5,6 @@ import java.io.Closeable; 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; @@ -16,7 +15,6 @@ import org.springframework.context.ApplicationEventPublisher; */ @Value @NonFinal -@CommonsLog public class TraceScope implements Closeable { private final ApplicationEventPublisher publisher; @@ -47,14 +45,14 @@ public class TraceScope implements Closeable { * * @return the same Span object */ - public Span detach() { + public SpanIdentifiers detach() { if (this.detached) { ExceptionUtils.error("Tried to detach trace span " + this.span + " but " + "it has already been detached."); } this.detached = true; - Span cur = TraceContextHolder.getCurrentSpan(); + 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 " + @@ -73,7 +71,7 @@ public class TraceScope implements Closeable { return; } this.detached = true; - Span cur = TraceContextHolder.getCurrentSpan(); + 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 " + diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/TraceAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/TraceAutoConfiguration.java index cc8782977..68809faf8 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/TraceAutoConfiguration.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/TraceAutoConfiguration.java @@ -25,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); } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceCallable.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceCallable.java index c2aaa1e1f..c77b19066 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceCallable.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceCallable.java @@ -2,9 +2,10 @@ package org.springframework.cloud.sleuth.instrument; import java.util.concurrent.Callable; +import lombok.EqualsAndHashCode; import lombok.Value; -import org.springframework.cloud.sleuth.Span; +import org.springframework.cloud.sleuth.SpanIdentifiers; import org.springframework.cloud.sleuth.Trace; import org.springframework.cloud.sleuth.TraceScope; @@ -12,27 +13,28 @@ import org.springframework.cloud.sleuth.TraceScope; * @author Spencer Gibb */ @Value +@EqualsAndHashCode(callSuper=false) public class TraceCallable extends TraceDelegate> implements Callable { public TraceCallable(Trace trace, Callable delagate) { super(trace, delagate); } - public TraceCallable(Trace trace, Callable delagate, Span parent) { - super(trace, delagate, parent); + public TraceCallable(Trace trace, Callable delegate, SpanIdentifiers parent) { + super(trace, delegate, parent); } - public TraceCallable(Trace trace, Callable delagate, Span parent, String name) { - super(trace, delagate, parent, name); + public TraceCallable(Trace trace, Callable delegate, SpanIdentifiers parent, String name) { + super(trace, delegate, parent, name); } @Override public V call() throws Exception { - if (this.parent != null) { + if (this.getParent() != null) { TraceScope scope = startSpan(); try { - return this.delagate.call(); + return this.getDelegate().call(); } finally { scope.close(); @@ -40,7 +42,7 @@ public class TraceCallable extends TraceDelegate> implements Call } else { - return this.delagate.call(); + return this.getDelegate().call(); } } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceDelegate.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceDelegate.java index 458de89d4..dca845b6c 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceDelegate.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceDelegate.java @@ -1,6 +1,8 @@ package org.springframework.cloud.sleuth.instrument; -import org.springframework.cloud.sleuth.Span; +import lombok.Getter; + +import org.springframework.cloud.sleuth.SpanIdentifiers; import org.springframework.cloud.sleuth.Trace; import org.springframework.cloud.sleuth.TraceContextHolder; import org.springframework.cloud.sleuth.TraceScope; @@ -8,24 +10,25 @@ import org.springframework.cloud.sleuth.TraceScope; /** * @author Spencer Gibb */ +@Getter public abstract class TraceDelegate { - protected final Trace trace; - protected final T delagate; - protected final Span parent; - protected final String name; - - public TraceDelegate(Trace trace, T delagate) { - this(trace, delagate, TraceContextHolder.getCurrentSpan(), null); + private final Trace trace; + private final T delegate; + private final SpanIdentifiers parent; + private final String name; + + public TraceDelegate(Trace trace, T delegate) { + this(trace, delegate, TraceContextHolder.getCurrentSpan(), null); } - public TraceDelegate(Trace trace, T delagate, Span parent) { - this(trace, delagate, parent, null); + public TraceDelegate(Trace trace, T delegate, SpanIdentifiers parent) { + this(trace, delegate, parent, null); } - public TraceDelegate(Trace trace, T delagate, Span parent, String name) { + public TraceDelegate(Trace trace, T delegate, SpanIdentifiers parent, String name) { this.trace = trace; - this.delagate = delagate; + this.delegate = delegate; this.parent = parent; this.name = name; } @@ -35,6 +38,6 @@ public abstract class TraceDelegate { } protected String getSpanName() { - return this.name == null ? Thread.currentThread().getName() : name; + return this.name == null ? Thread.currentThread().getName() : this.name; } } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceRunnable.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceRunnable.java index 4a46cb32d..0b29eb006 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceRunnable.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceRunnable.java @@ -3,7 +3,7 @@ package org.springframework.cloud.sleuth.instrument; import lombok.EqualsAndHashCode; import lombok.Value; -import org.springframework.cloud.sleuth.Span; +import org.springframework.cloud.sleuth.SpanIdentifiers; import org.springframework.cloud.sleuth.Trace; import org.springframework.cloud.sleuth.TraceScope; @@ -18,28 +18,28 @@ public class TraceRunnable extends TraceDelegate implements Runnable { super(trace, delagate); } - public TraceRunnable(Trace trace, Runnable delagate, Span parent) { + public TraceRunnable(Trace trace, Runnable delagate, SpanIdentifiers parent) { super(trace, delagate, parent); } - public TraceRunnable(Trace trace, Runnable delagate, Span parent, String name) { + public TraceRunnable(Trace trace, Runnable delagate, SpanIdentifiers parent, String name) { super(trace, delagate, parent, name); } @Override public void run() { - if (this.parent != null) { + if (this.getParent() != null) { TraceScope scope = startSpan(); try { - this.delagate.run(); + this.getDelegate().run(); } finally { scope.close(); } } else { - this.delagate.run(); + this.getDelegate().run(); } } } 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 f43913d87..e4edea0b7 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 @@ -79,7 +79,7 @@ public class TraceFilter extends OncePerRequestFilter { if (!skip) { String spanId = getHeader(request, response, SPAN_ID_NAME); String traceId = getHeader(request, response, TRACE_ID_NAME); - String name = this.urlPathHelper.getPathWithinApplication(request); + String name = "http" + this.urlPathHelper.getPathWithinApplication(request); if (hasText(spanId) && hasText(traceId)) { TraceInfo traceInfo = new TraceInfo(traceId, spanId); diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/sampler/AlwaysSampler.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/sampler/AlwaysSampler.java index 087912506..5cfb80e30 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/sampler/AlwaysSampler.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/sampler/AlwaysSampler.java @@ -5,9 +5,9 @@ import org.springframework.cloud.sleuth.Sampler; /** * @author Spencer Gibb */ -public class AlwaysSampler implements Sampler { +public class AlwaysSampler implements Sampler { @Override - public boolean next(Object info) { + public boolean next(Void info) { return true; } } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/sampler/IsTracingSampler.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/sampler/IsTracingSampler.java index 3c8eaaf07..b05b772e6 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/sampler/IsTracingSampler.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/sampler/IsTracingSampler.java @@ -6,10 +6,10 @@ import org.springframework.cloud.sleuth.TraceContextHolder; /** * @author Spencer Gibb */ -public class IsTracingSampler implements Sampler { +public class IsTracingSampler implements Sampler { @Override - public boolean next(Object info) { + public boolean next(Void info) { return TraceContextHolder.getCurrentSpan() != null; } } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/slf4j/Slf4jSpanStartedListener.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/slf4j/Slf4jSpanStartedListener.java index 7708340e0..9106f20fa 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/slf4j/Slf4jSpanStartedListener.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/slf4j/Slf4jSpanStartedListener.java @@ -3,7 +3,7 @@ package org.springframework.cloud.sleuth.slf4j; import lombok.extern.slf4j.Slf4j; import org.slf4j.MDC; -import org.springframework.cloud.sleuth.Span; +import org.springframework.cloud.sleuth.SpanIdentifiers; import org.springframework.cloud.sleuth.Trace; import org.springframework.cloud.sleuth.event.SpanStartedEvent; import org.springframework.context.ApplicationListener; @@ -16,7 +16,7 @@ public class Slf4jSpanStartedListener implements ApplicationListener defaultSampler; + private final Sampler defaultSampler; private final IdGenerator idGenerator; private final ApplicationEventPublisher publisher; - public DefaultTrace(Sampler defaultSampler, IdGenerator idGenerator, + public DefaultTrace(Sampler defaultSampler, IdGenerator idGenerator, ApplicationEventPublisher publisher) { this.defaultSampler = defaultSampler; this.idGenerator = idGenerator; @@ -37,75 +37,45 @@ public class DefaultTrace implements Trace { } @Override - public TraceScope startSpan(String name) { - return this.startSpan(name, this.defaultSampler); - } - - @Override - public TraceScope startSpan(String name, TraceInfo tinfo) { - if (tinfo == null) return doStart(null); - MilliSpan span = MilliSpan.builder() - .begin(System.currentTimeMillis()) - .name(name) - .traceId(tinfo.getTraceId()) - .spanId(this.idGenerator.create()) - .parent(tinfo.getSpanId()) - .build(); - return doStart(span); - } - - @Override - public TraceScope startSpan(String name, Span parent) { + public TraceScope startSpan(String name, SpanIdentifiers parent) { if (parent == null) { return startSpan(name); } - Span currentSpan = getCurrentSpan(); - if ((currentSpan != null) && (currentSpan != parent)) { - error("HTrace client error: thread " + - Thread.currentThread().getName() + " tried to start a new Span " + - "with parent " + parent.toString() + ", but there is already a " + - "currentSpan " + currentSpan); + SpanIdentifiers currentSpan = getCurrentSpan(); + if (currentSpan != null && !parent.equals(currentSpan)) { + error("HTrace client error: thread " + Thread.currentThread().getName() + + " tried to start a new Span " + "with parent " + parent.toString() + + ", but there is already a " + "currentSpan " + currentSpan); } return doStart(createChild(parent, name)); } @Override - public TraceScope startSpan(String name, Sampler s) { - return startSpan(name, s, null); + public TraceScope startSpan(String name) { + return this.startSpan(name, this.defaultSampler, null); } @Override public TraceScope startSpan(String name, Sampler s, T info) { Span span = null; if (TraceContextHolder.isTracing() || s.next(info)) { - span = createNew(name); + span = createChild(getCurrentSpan(), name); } return doStart(span); } - protected Span createNew(String name) { - Span parent = getCurrentSpan(); + protected Span createChild(SpanIdentifiers parent, String name) { if (parent == null) { - return MilliSpan.builder() - .begin(System.currentTimeMillis()) - .name(name) - .traceId(this.idGenerator.create()) - .spanId(this.idGenerator.create()) + return MilliSpan.builder().begin(System.currentTimeMillis()).name(name) + .traceId(this.idGenerator.create()).spanId(this.idGenerator.create()) + .build(); + } + else { + return MilliSpan.builder().begin(System.currentTimeMillis()).name(name) + .traceId(parent.getTraceId()).parent(parent.getSpanId()) + .spanId(this.idGenerator.create()).processId(parent.getProcessId()) .build(); - } else { - return createChild(parent, name); } - } - - protected Span createChild(Span parent, String childname) { - return MilliSpan.builder() - .begin(System.currentTimeMillis()) - .name(childname) - .traceId(parent.getTraceId()) - .parent(parent.getSpanId()) - .spanId(this.idGenerator.create()) - .processId(parent.getProcessId()) - .build(); } protected TraceScope doStart(Span span) { @@ -118,7 +88,8 @@ public class DefaultTrace implements Trace { @Override public TraceScope continueSpan(Span span) { // Return an empty TraceScope that does nothing on close - if (span == null) return NullScope.INSTANCE; + if (span == null) + return NullScope.INSTANCE; Span oldSpan = getCurrentSpan(); TraceContextHolder.setCurrentSpan(span); return new TraceScope(this.publisher, span, oldSpan); @@ -144,7 +115,8 @@ public class DefaultTrace implements Trace { @Override public Callable wrap(Callable callable) { if (TraceContextHolder.isTracing()) { - return new TraceCallable<>(this, callable, TraceContextHolder.getCurrentSpan()); + return new TraceCallable<>(this, callable, + TraceContextHolder.getCurrentSpan()); } return callable; } diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/DefaultTraceTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/DefaultTraceTests.java index ca2444369..23dccbc66 100644 --- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/DefaultTraceTests.java +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/DefaultTraceTests.java @@ -2,8 +2,8 @@ package org.springframework.cloud.sleuth; 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.isA; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -38,7 +38,7 @@ public class DefaultTraceTests { DefaultTrace trace = new DefaultTrace(new IsTracingSampler(), new RandomUuidGenerator(), publisher); - TraceScope scope = trace.startSpan(CREATE_SIMPLE_TRACE, new AlwaysSampler()); + TraceScope scope = trace.startSpan(CREATE_SIMPLE_TRACE, new AlwaysSampler(), null); try { importantWork1(trace); } @@ -62,15 +62,15 @@ public class DefaultTraceTests { assertThat("spans was wrong size", spans.size(), is(NUM_SPANS)); - Span root = assertSpan(spans, null, CREATE_SIMPLE_TRACE); - Span child = assertSpan(spans, root.getSpanId(), IMPORTANT_WORK_1); - Span grandChild = assertSpan(spans, child.getSpanId(), IMPORTANT_WORK_2); + SpanIdentifiers root = assertSpan(spans, null, CREATE_SIMPLE_TRACE); + SpanIdentifiers child = assertSpan(spans, root.getSpanId(), IMPORTANT_WORK_1); + SpanIdentifiers grandChild = assertSpan(spans, child.getSpanId(), IMPORTANT_WORK_2); List gen4 = findSpans(spans, grandChild.getSpanId()); assertThat("gen4 was non-empty", gen4.isEmpty(), is(true)); } - private Span assertSpan(List spans, String parentId, String name) { + private SpanIdentifiers assertSpan(List spans, String parentId, String name) { List found = findSpans(spans, parentId); assertThat("more than one span with parentId " + parentId, found.size(), is(1)); Span span = found.get(0); 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 9a0f08aec..bcb833d8f 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 @@ -1,7 +1,5 @@ package org.springframework.cloud.sleuth.sample; -import com.github.kristofa.brave.LoggingSpanCollectorImpl; -import com.github.kristofa.brave.SpanCollector; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.cloud.sleuth.Sampler; diff --git a/spring-cloud-sleuth-sample/src/main/java/org/springframework/cloud/sleuth/sample/SampleController.java b/spring-cloud-sleuth-sample/src/main/java/org/springframework/cloud/sleuth/sample/SampleController.java index 1f571e7bb..21e202361 100644 --- a/spring-cloud-sleuth-sample/src/main/java/org/springframework/cloud/sleuth/sample/SampleController.java +++ b/spring-cloud-sleuth-sample/src/main/java/org/springframework/cloud/sleuth/sample/SampleController.java @@ -8,7 +8,7 @@ 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.SpanIdentifiers; import org.springframework.cloud.sleuth.Trace; import org.springframework.cloud.sleuth.TraceContextHolder; import org.springframework.cloud.sleuth.TraceScope; @@ -47,7 +47,7 @@ ApplicationListener { return new Callable() { @Override public String call() throws Exception { - Span currentSpan = TraceContextHolder.getCurrentSpan(); + SpanIdentifiers currentSpan = TraceContextHolder.getCurrentSpan(); return "async hi: "+currentSpan; } }; @@ -67,7 +67,7 @@ ApplicationListener { @SneakyThrows @RequestMapping("/traced") public String traced() { - TraceScope scope = this.trace.startSpan("customTraceEndpoint", new AlwaysSampler()); + TraceScope scope = this.trace.startSpan("customTraceEndpoint", new AlwaysSampler(), null); final Random random = new Random(); int millis = random.nextInt(1000); log.info("Sleeping for {} millis", millis); diff --git a/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/SleuthTracer.java b/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/SleuthTracer.java index 9a9682255..0aae54d47 100644 --- a/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/SleuthTracer.java +++ b/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/SleuthTracer.java @@ -13,8 +13,11 @@ import lombok.extern.apachecommons.CommonsLog; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.web.ServerProperties; +import org.springframework.cloud.sleuth.SpanIdentifiers; import org.springframework.cloud.sleuth.Span; import org.springframework.cloud.sleuth.TimelineAnnotation; +import org.springframework.cloud.sleuth.event.SpanStoppedEvent; +import org.springframework.context.event.EventListener; import com.github.kristofa.brave.SpanCollector; import com.twitter.zipkin.gen.Annotation; @@ -22,8 +25,6 @@ import com.twitter.zipkin.gen.AnnotationType; import com.twitter.zipkin.gen.BinaryAnnotation; import com.twitter.zipkin.gen.Endpoint; import com.twitter.zipkin.gen.zipkinCoreConstants; -import org.springframework.cloud.sleuth.event.SpanStoppedEvent; -import org.springframework.context.event.EventListener; /** * @author Spencer Gibb @@ -47,7 +48,7 @@ public class SleuthTracer { } /** - * Converts a given HTrace span to a Zipkin Span. + * Converts a given Sleuth span to a Zipkin Span. *
    *
  • First set the start annotation. [CS, SR], depending whether it is a client service or not. *
  • Set other id's, etc [TraceId's etc] @@ -82,8 +83,8 @@ public class SleuthTracer { public Integer getPort() { Integer port; - if (serverProperties.getPort() != null) { - port = serverProperties.getPort(); + if (this.serverProperties.getPort() != null) { + port = this.serverProperties.getPort(); } else { port = 8080; //TODO: support random port } @@ -92,20 +93,20 @@ public class SleuthTracer { public int getAddress() { String address; - if (serverProperties.getAddress() != null) { - address = serverProperties.getAddress().getHostAddress(); + if (this.serverProperties.getAddress() != null) { + address = this.serverProperties.getAddress().getHostAddress(); } else { address = "127.0.0.1"; //TODO: get address from config } return ipAddressToInt(address); } - public String getServiceName(Span span) { + public String getServiceName(SpanIdentifiers span) { String serviceName; if (span.getProcessId() != null) { serviceName = span.getProcessId().toLowerCase(); } else { - serviceName = appName; + serviceName = this.appName; } return serviceName; } @@ -125,21 +126,21 @@ public class SleuthTracer { * Add annotations from the sleuth Span. */ private List createZipkinAnnotations(Span span, - Endpoint ep) { + Endpoint endpoint) { List annotationList = new ArrayList<>(); int duration = (int)(span.getEnd() - span.getBegin()); // add first zipkin annotation. - annotationList.add(createZipkinAnnotation(zipkinCoreConstants.CLIENT_SEND, span.getBegin(), 0, ep, true)); - annotationList.add(createZipkinAnnotation(zipkinCoreConstants.SERVER_RECV, span.getBegin(), 0, ep, true)); + annotationList.add(createZipkinAnnotation(zipkinCoreConstants.CLIENT_SEND, span.getBegin(), 0, endpoint, true)); + annotationList.add(createZipkinAnnotation(zipkinCoreConstants.SERVER_RECV, span.getBegin(), 0, endpoint, true)); // add sleuth time annotation for (TimelineAnnotation ta : span.getTimelineAnnotations()) { - annotationList.add(createZipkinAnnotation(ta.getMsg(), ta.getTime(), 0, ep, true)); + annotationList.add(createZipkinAnnotation(ta.getMsg(), ta.getTime(), 0, endpoint, true)); } // add last zipkin annotation - annotationList.add(createZipkinAnnotation(zipkinCoreConstants.SERVER_SEND, span.getEnd(), duration, ep, false)); - annotationList.add(createZipkinAnnotation(zipkinCoreConstants.CLIENT_RECV, span.getEnd(), duration, ep, false)); + annotationList.add(createZipkinAnnotation(zipkinCoreConstants.SERVER_SEND, span.getEnd(), duration, endpoint, false)); + annotationList.add(createZipkinAnnotation(zipkinCoreConstants.CLIENT_RECV, span.getEnd(), duration, endpoint, false)); return annotationList; } @@ -149,7 +150,7 @@ public class SleuthTracer { * @return list of Annotations that could be added to Zipkin Span. */ private List createZipkinBinaryAnnotations(Span span, - Endpoint ep) { + Endpoint endpoint) { List l = new ArrayList<>(); for (Map.Entry e : span.getKVAnnotations().entrySet()) { BinaryAnnotation binaryAnn = new BinaryAnnotation(); @@ -160,7 +161,7 @@ public class SleuthTracer { } catch (UnsupportedEncodingException ex) { log.error("Error encoding string as UTF-8", ex); } - binaryAnn.setHost(ep); + binaryAnn.setHost(endpoint); l.add(binaryAnn); } return l; @@ -171,13 +172,13 @@ public class SleuthTracer { * * @param value Annotation value * @param time timestamp will be extracted - * @param ep the endopint this annotation will be associated with. + * @param endpoint the endpoint this annotation will be associated with. * @param sendRequest use the first or last timestamp. */ private static Annotation createZipkinAnnotation(String value, long time, int duration, - Endpoint ep, boolean sendRequest) { + Endpoint endpoint, boolean sendRequest) { Annotation annotation = new Annotation(); - annotation.setHost(ep); + annotation.setHost(endpoint); // Zipkin is in microseconds if (sendRequest) { 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 18a0702ed..41c9716ca 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,6 +3,7 @@ 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.event.SpanStartedEvent; import org.springframework.cloud.sleuth.event.SpanStoppedEvent; @@ -64,7 +65,7 @@ public class ZipkinSpanListener { return context.getName(); } - protected void postTrace(Span context) { + protected void postTrace(SpanIdentifiers context) { // 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."); From af030545730e99327db8d0ab26f28baaf9be8791 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Wed, 29 Jul 2015 13:52:31 +0100 Subject: [PATCH 2/3] Separate parent and child a bit more in ZipkinSpanListener --- ...aceInfo.java => BasicSpanIdentifiers.java} | 2 +- .../cloud/sleuth/TraceScope.java | 39 +++++++++++-------- .../cloud/sleuth/event/SpanStartedEvent.java | 11 +++++- .../cloud/sleuth/event/SpanStoppedEvent.java | 11 +++++- .../sleuth/instrument/web/TraceFilter.java | 8 ++-- .../instrument/zuul/TracePreFilter.java | 4 +- .../cloud/sleuth/trace/DefaultTrace.java | 19 ++++----- .../sleuth/sample/SampleApplication.java | 6 ++- .../zipkin/ZipkinAutoConfiguration.java | 4 +- .../sleuth/zipkin/ZipkinSpanListener.java | 34 ++++++---------- 10 files changed, 75 insertions(+), 63 deletions(-) rename spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/{TraceInfo.java => BasicSpanIdentifiers.java} (75%) 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."); From 15db0805429ce52d5580364432cf7c32008d5942 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Wed, 29 Jul 2015 17:27:33 +0100 Subject: [PATCH 3/3] Stop using Brave client/server senders in favour of the collector Directly using the collector gives us more control of the annotations. The main improvement/change here is that we need to send the span name and parent details downstream as well as the span id. It's not logically required by the trace model, but zipkin needs it, so it can set annotations on the parent span (server recv/send). --- .../cloud/sleuth/BasicSpanIdentifiers.java | 13 - .../cloud/sleuth/NullScope.java | 2 +- .../springframework/cloud/sleuth/Span.java | 50 ++-- .../springframework/cloud/sleuth/Trace.java | 9 +- .../cloud/sleuth/TraceScope.java | 6 +- .../ClientReceivedEvent.java} | 38 ++- .../cloud/sleuth/event/ClientSentEvent.java | 40 ++++ .../cloud/sleuth/event/SpanStartedEvent.java | 5 +- .../cloud/sleuth/event/SpanStoppedEvent.java | 5 +- .../sleuth/instrument/TraceCallable.java | 10 +- .../sleuth/instrument/TraceDelegate.java | 8 +- .../sleuth/instrument/TraceRunnable.java | 6 +- .../sleuth/instrument/web/TraceFilter.java | 23 +- .../client/TraceRestTemplateInterceptor.java | 50 +++- .../instrument/zuul/TracePostFilter.java | 46 ---- .../instrument/zuul/TracePreFilter.java | 65 ----- .../zuul/TraceZuulAutoConfiguration.java | 28 --- .../slf4j/SleuthSlf4jAutoConfiguration.java | 8 +- .../cloud/sleuth/slf4j/Slf4jSpanListener.java | 46 ++++ .../slf4j/Slf4jSpanStartedListener.java | 25 -- .../slf4j/Slf4jSpanStoppedListener.java | 24 -- .../cloud/sleuth/trace/DefaultTrace.java | 10 +- .../cloud/sleuth/DefaultTraceTests.java | 8 +- .../sleuth/sample/SampleApplication.java | 8 +- .../cloud/sleuth/sample/SampleController.java | 4 +- .../src/main/resources/application.yml | 2 +- .../cloud/sleuth/zipkin/SleuthTracer.java | 207 ---------------- .../zipkin/ZipkinAutoConfiguration.java | 17 +- .../sleuth/zipkin/ZipkinSpanListener.java | 224 +++++++++++++++--- 29 files changed, 443 insertions(+), 544 deletions(-) delete mode 100644 spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/BasicSpanIdentifiers.java rename spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/{SpanIdentifiers.java => event/ClientReceivedEvent.java} (54%) create mode 100644 spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/event/ClientSentEvent.java delete mode 100644 spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TracePostFilter.java delete mode 100644 spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TracePreFilter.java delete mode 100644 spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TraceZuulAutoConfiguration.java create mode 100644 spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/slf4j/Slf4jSpanListener.java delete mode 100644 spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/slf4j/Slf4jSpanStartedListener.java delete mode 100644 spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/slf4j/Slf4jSpanStoppedListener.java delete mode 100644 spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/SleuthTracer.java diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/BasicSpanIdentifiers.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/BasicSpanIdentifiers.java deleted file mode 100644 index 0291f063a..000000000 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/BasicSpanIdentifiers.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.springframework.cloud.sleuth; - -import lombok.Data; - -/** - * @author Spencer Gibb - */ -@Data -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/NullScope.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/NullScope.java index 72f849a94..82bad3bcf 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/NullScope.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/NullScope.java @@ -15,7 +15,7 @@ public final class NullScope extends TraceScope { } @Override - public SpanIdentifiers detach() { + public Span detach() { return null; } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Span.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Span.java index 7fbad8562..0e9a45e9a 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Span.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Span.java @@ -11,7 +11,41 @@ import java.util.Map; * to keep following the parents of a span until you arrive at a span with no * parents.

    */ -public interface Span extends SpanIdentifiers { +public interface Span { + + /** + * A human-readable name assigned to this span instance.

    + */ + String getName(); + + /** + * A pseudo-unique (random) number assigned to this span instance.

    + *

    + * The spanId is immutable and cannot be changed. It is safe to access this + * from multiple threads. + */ + String getSpanId(); + + /** + * A pseudo-unique (random) number assigned to the trace associated with this + * span + */ + String getTraceId(); + + /** + * Return a unique id for the process from which this Span originated.

    + *

    + * Will never be null. + */ + String getProcessId(); + + /** + * Returns the parent IDs of the span.

    + *

    + * The collection will be empty if there are no parents. + */ + List getParents(); + /** * The block has completed, stop the clock */ @@ -38,20 +72,6 @@ public interface Span extends SpanIdentifiers { */ boolean isRunning(); - /** - * Return a textual name of this span.

    - *

    - * Will never be null. - */ - String getName(); - - /** - * Returns the parent IDs of the span.

    - *

    - * The collection will be empty if there are no parents. - */ - List getParents(); - /** * Add a data annotation associated with this span */ diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Trace.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Trace.java index 5f682b201..601890e87 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Trace.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Trace.java @@ -35,8 +35,11 @@ import java.util.concurrent.Callable; */ public interface Trace { - String SPAN_ID_NAME = "Span-Id"; - String TRACE_ID_NAME = "Trace-Id"; + String SPAN_ID_NAME = "X-Span-Id"; + String TRACE_ID_NAME = "X-Trace-Id"; + String SPAN_NAME_NAME = "X-Span-Name"; + String PARENT_ID_NAME = "X-Parent-Id"; + String PROCESS_ID_NAME = "X-Process-Id"; /** * Creates a trace scope wrapping a new span. @@ -59,7 +62,7 @@ public interface Trace { * * @param name The name field for the new span to create. */ - TraceScope startSpan(String name, SpanIdentifiers parent); + TraceScope startSpan(String name, Span parent); /** * Start a new span if the sampler allows it or if we are already tracing in this 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 b92de4f54..a61df5bf4 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 @@ -45,14 +45,14 @@ public class TraceScope implements Closeable { * * @return the same Span object */ - public SpanIdentifiers detach() { + public Span detach() { if (this.detached) { ExceptionUtils.error("Tried to detach trace span " + this.span + " but " + "it has already been detached."); } this.detached = true; - SpanIdentifiers cur = TraceContextHolder.getCurrentSpan(); + Span 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 " @@ -72,7 +72,7 @@ public class TraceScope implements Closeable { return; } this.detached = true; - SpanIdentifiers cur = TraceContextHolder.getCurrentSpan(); + Span 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 " diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/SpanIdentifiers.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/event/ClientReceivedEvent.java similarity index 54% rename from spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/SpanIdentifiers.java rename to spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/event/ClientReceivedEvent.java index ae82491a3..92e3dd657 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/SpanIdentifiers.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/event/ClientReceivedEvent.java @@ -14,33 +14,27 @@ * limitations under the License. */ -package org.springframework.cloud.sleuth; +package org.springframework.cloud.sleuth.event; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +import org.springframework.cloud.sleuth.Span; +import org.springframework.context.ApplicationEvent; /** * @author Dave Syer * */ -public interface SpanIdentifiers { +@Data +@EqualsAndHashCode(callSuper = false) +@SuppressWarnings("serial") +public class ClientReceivedEvent extends ApplicationEvent { - /** - * A pseudo-unique (random) number assigned to this span instance.

    - *

    - * The spanId is immutable and cannot be changed. It is safe to access this - * from multiple threads. - */ - String getSpanId(); - - /** - * A pseudo-unique (random) number assigned to the trace associated with this - * span - */ - String getTraceId(); - - /** - * Return a unique id for the process from which this Span originated.

    - *

    - * Will never be null. - */ - String getProcessId(); + private final Span span; + public ClientReceivedEvent(Object source, Span span) { + super(source); + this.span = span; + } } \ No newline at end of file diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/event/ClientSentEvent.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/event/ClientSentEvent.java new file mode 100644 index 000000000..642b7f592 --- /dev/null +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/event/ClientSentEvent.java @@ -0,0 +1,40 @@ +/* + * Copyright 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.event; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +import org.springframework.cloud.sleuth.Span; +import org.springframework.context.ApplicationEvent; + +/** + * @author Dave Syer + * + */ +@Data +@EqualsAndHashCode(callSuper = false) +@SuppressWarnings("serial") +public class ClientSentEvent extends ApplicationEvent { + + private final Span span; + + public ClientSentEvent(Object source, Span span) { + super(source); + this.span = span; + } +} \ No newline at end of file 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 676db75b3..abcca95de 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 @@ -4,7 +4,6 @@ import lombok.Data; import lombok.EqualsAndHashCode; import org.springframework.cloud.sleuth.Span; -import org.springframework.cloud.sleuth.SpanIdentifiers; import org.springframework.context.ApplicationEvent; /** @@ -15,14 +14,14 @@ import org.springframework.context.ApplicationEvent; @SuppressWarnings("serial") public class SpanStartedEvent extends ApplicationEvent { - private final SpanIdentifiers parent; + private final Span parent; private final Span span; public SpanStartedEvent(Object source, Span span) { this(source, null, span); } - public SpanStartedEvent(Object source, SpanIdentifiers parent, Span span) { + public SpanStartedEvent(Object source, Span 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 d9ab4c07d..eec98d16b 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 @@ -4,7 +4,6 @@ import lombok.Data; import lombok.EqualsAndHashCode; import org.springframework.cloud.sleuth.Span; -import org.springframework.cloud.sleuth.SpanIdentifiers; import org.springframework.context.ApplicationEvent; /** @@ -16,13 +15,13 @@ import org.springframework.context.ApplicationEvent; public class SpanStoppedEvent extends ApplicationEvent { private final Span span; - private final SpanIdentifiers parent; + private final Span parent; public SpanStoppedEvent(Object source, Span span) { this(source, null, span); } - public SpanStoppedEvent(Object source, SpanIdentifiers parent, Span span) { + public SpanStoppedEvent(Object source, Span 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/TraceCallable.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceCallable.java index c77b19066..2946cdcc9 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceCallable.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceCallable.java @@ -5,7 +5,7 @@ import java.util.concurrent.Callable; import lombok.EqualsAndHashCode; import lombok.Value; -import org.springframework.cloud.sleuth.SpanIdentifiers; +import org.springframework.cloud.sleuth.Span; import org.springframework.cloud.sleuth.Trace; import org.springframework.cloud.sleuth.TraceScope; @@ -16,15 +16,15 @@ import org.springframework.cloud.sleuth.TraceScope; @EqualsAndHashCode(callSuper=false) public class TraceCallable extends TraceDelegate> implements Callable { - public TraceCallable(Trace trace, Callable delagate) { - super(trace, delagate); + public TraceCallable(Trace trace, Callable delegate) { + super(trace, delegate); } - public TraceCallable(Trace trace, Callable delegate, SpanIdentifiers parent) { + public TraceCallable(Trace trace, Callable delegate, Span parent) { super(trace, delegate, parent); } - public TraceCallable(Trace trace, Callable delegate, SpanIdentifiers parent, String name) { + public TraceCallable(Trace trace, Callable delegate, Span parent, String name) { super(trace, delegate, parent, name); } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceDelegate.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceDelegate.java index dca845b6c..074ed1df3 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceDelegate.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceDelegate.java @@ -2,7 +2,7 @@ package org.springframework.cloud.sleuth.instrument; import lombok.Getter; -import org.springframework.cloud.sleuth.SpanIdentifiers; +import org.springframework.cloud.sleuth.Span; import org.springframework.cloud.sleuth.Trace; import org.springframework.cloud.sleuth.TraceContextHolder; import org.springframework.cloud.sleuth.TraceScope; @@ -15,18 +15,18 @@ public abstract class TraceDelegate { private final Trace trace; private final T delegate; - private final SpanIdentifiers parent; + private final Span parent; private final String name; public TraceDelegate(Trace trace, T delegate) { this(trace, delegate, TraceContextHolder.getCurrentSpan(), null); } - public TraceDelegate(Trace trace, T delegate, SpanIdentifiers parent) { + public TraceDelegate(Trace trace, T delegate, Span parent) { this(trace, delegate, parent, null); } - public TraceDelegate(Trace trace, T delegate, SpanIdentifiers parent, String name) { + public TraceDelegate(Trace trace, T delegate, Span parent, String name) { this.trace = trace; this.delegate = delegate; this.parent = parent; diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceRunnable.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceRunnable.java index 0b29eb006..56bfdc124 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceRunnable.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceRunnable.java @@ -3,7 +3,7 @@ package org.springframework.cloud.sleuth.instrument; import lombok.EqualsAndHashCode; import lombok.Value; -import org.springframework.cloud.sleuth.SpanIdentifiers; +import org.springframework.cloud.sleuth.Span; import org.springframework.cloud.sleuth.Trace; import org.springframework.cloud.sleuth.TraceScope; @@ -18,11 +18,11 @@ public class TraceRunnable extends TraceDelegate implements Runnable { super(trace, delagate); } - public TraceRunnable(Trace trace, Runnable delagate, SpanIdentifiers parent) { + public TraceRunnable(Trace trace, Runnable delagate, Span parent) { super(trace, delagate, parent); } - public TraceRunnable(Trace trace, Runnable delagate, SpanIdentifiers parent, String name) { + public TraceRunnable(Trace trace, Runnable delagate, Span parent, String name) { super(trace, delagate, parent, name); } 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 4fd286244..3918fe0ad 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 @@ -15,7 +15,10 @@ */ package org.springframework.cloud.sleuth.instrument.web; +import static org.springframework.cloud.sleuth.Trace.PARENT_ID_NAME; +import static org.springframework.cloud.sleuth.Trace.PROCESS_ID_NAME; import static org.springframework.cloud.sleuth.Trace.SPAN_ID_NAME; +import static org.springframework.cloud.sleuth.Trace.SPAN_NAME_NAME; import static org.springframework.cloud.sleuth.Trace.TRACE_ID_NAME; import static org.springframework.util.StringUtils.hasText; @@ -27,7 +30,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.MilliSpan; +import org.springframework.cloud.sleuth.MilliSpan.MilliSpanBuilder; import org.springframework.cloud.sleuth.Trace; import org.springframework.cloud.sleuth.TraceScope; import org.springframework.core.Ordered; @@ -82,9 +86,22 @@ public class TraceFilter extends OncePerRequestFilter { String name = "http" + uri; if (hasText(spanId) && hasText(traceId)) { - BasicSpanIdentifiers traceInfo = new BasicSpanIdentifiers(traceId, spanId); + MilliSpanBuilder traceInfo = MilliSpan.builder().traceId(traceId).spanId(spanId); + String parentId = getHeader(request, response, PARENT_ID_NAME); + String processId = getHeader(request, response, PROCESS_ID_NAME); + String parentName = getHeader(request, response, SPAN_NAME_NAME); + if (parentName!=null) { + traceInfo.name(parentName); + } + if (processId!=null) { + traceInfo.processId(processId); + } + if (parentId!=null) { + traceInfo.parent(parentId); + } + // TODO: trace description? - traceScope = this.trace.startSpan(name, traceInfo); + traceScope = this.trace.startSpan(name, traceInfo.build()); // Send new span id back addToResponseIfNotPresent(response, SPAN_ID_NAME, traceScope.getSpan() .getSpanId()); diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceRestTemplateInterceptor.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceRestTemplateInterceptor.java index 3be3db292..32c09aef5 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceRestTemplateInterceptor.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceRestTemplateInterceptor.java @@ -15,22 +15,31 @@ */ package org.springframework.cloud.sleuth.instrument.web.client; +import static org.springframework.cloud.sleuth.Trace.PARENT_ID_NAME; +import static org.springframework.cloud.sleuth.Trace.PROCESS_ID_NAME; import static org.springframework.cloud.sleuth.Trace.SPAN_ID_NAME; +import static org.springframework.cloud.sleuth.Trace.SPAN_NAME_NAME; import static org.springframework.cloud.sleuth.Trace.TRACE_ID_NAME; import static org.springframework.cloud.sleuth.TraceContextHolder.getCurrentSpan; import static org.springframework.cloud.sleuth.TraceContextHolder.isTracing; import java.io.IOException; +import org.springframework.cloud.sleuth.Span; import org.springframework.cloud.sleuth.Trace; +import org.springframework.cloud.sleuth.event.ClientReceivedEvent; +import org.springframework.cloud.sleuth.event.ClientSentEvent; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.http.HttpRequest; import org.springframework.http.client.ClientHttpRequestExecution; import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.ClientHttpResponse; /** - * Interceptor that verifies whether the trance and span id has been set on the - * request and sets them if one or both of them are missing. + * Interceptor that verifies whether the trance and span id has been set on the request + * and sets them if one or both of them are missing. * * @see org.springframework.web.client.RestTemplate * @see Trace @@ -38,14 +47,47 @@ import org.springframework.http.client.ClientHttpResponse; * @author Marcin Grzejszczak, 4financeIT * @author Spencer Gibb */ -public class TraceRestTemplateInterceptor implements ClientHttpRequestInterceptor { +public class TraceRestTemplateInterceptor implements ClientHttpRequestInterceptor, +ApplicationEventPublisherAware { + + private ApplicationEventPublisher publisher; + + @Override + public void setApplicationEventPublisher(ApplicationEventPublisher publisher) { + this.publisher = publisher; + } @Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { setHeader(request, SPAN_ID_NAME, getCurrentSpan().getSpanId()); setHeader(request, TRACE_ID_NAME, getCurrentSpan().getTraceId()); - return execution.execute(request, body); + setHeader(request, SPAN_NAME_NAME, getCurrentSpan().getName()); + String parentId = getParentId(getCurrentSpan()); + if (parentId != null) { + setHeader(request, PARENT_ID_NAME, parentId); + } + String processId = getCurrentSpan().getProcessId(); + if (processId != null) { + setHeader(request, PROCESS_ID_NAME, processId); + } + publish(new ClientSentEvent(this, getCurrentSpan())); + try { + return execution.execute(request, body); + } finally { + publish(new ClientReceivedEvent(this, getCurrentSpan())); + } + } + + private void publish(ApplicationEvent event) { + if (this.publisher !=null) { + this.publisher.publishEvent(event); + } + } + + private String getParentId(Span span) { + return span.getParents() != null && !span.getParents().isEmpty() ? span + .getParents().get(0) : null; } public void setHeader(HttpRequest request, String name, String value) { diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TracePostFilter.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TracePostFilter.java deleted file mode 100644 index 910dbadb3..000000000 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TracePostFilter.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.springframework.cloud.sleuth.instrument.zuul; - -import org.springframework.cloud.sleuth.Trace; -import org.springframework.cloud.sleuth.TraceScope; - -import com.netflix.zuul.ZuulFilter; -import com.netflix.zuul.context.RequestContext; - -/** - * @author Spencer Gibb - */ -public class TracePostFilter extends ZuulFilter { - - private Trace trace; - - public TracePostFilter(Trace trace) { - this.trace = trace; - } - - @Override - public String filterType() { - return "post"; - } - - @Override - public int filterOrder() { - return 0; - } - - @Override - public boolean shouldFilter() { - return true; - } - - @Override - public Object run() { - TraceScope traceScope = (TraceScope) RequestContext.getCurrentContext().get( - "traceScope"); - - if (traceScope != null) { - traceScope.close(); - } - - return null; - } -} 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 deleted file mode 100644 index 7bd3767f1..000000000 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TracePreFilter.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.springframework.cloud.sleuth.instrument.zuul; - -import static org.springframework.cloud.sleuth.Trace.SPAN_ID_NAME; -import static org.springframework.cloud.sleuth.Trace.TRACE_ID_NAME; -import static org.springframework.util.StringUtils.hasText; - -import javax.servlet.http.HttpServletRequest; - -import org.springframework.cloud.sleuth.Trace; -import org.springframework.cloud.sleuth.BasicSpanIdentifiers; -import org.springframework.cloud.sleuth.TraceScope; - -import com.netflix.zuul.ZuulFilter; -import com.netflix.zuul.context.RequestContext; - -/** - * @author Spencer Gibb - */ -public class TracePreFilter extends ZuulFilter { - - private Trace trace; - - public TracePreFilter(Trace trace) { - this.trace = trace; - } - - @Override - public String filterType() { - return "pre"; - } - - @Override - public int filterOrder() { - return 0; - } - - @Override - public boolean shouldFilter() { - return true; - } - - @Override - public Object run() { - RequestContext context = RequestContext.getCurrentContext(); - HttpServletRequest request = context.getRequest(); - - String spanId = request.getHeader(SPAN_ID_NAME); - String traceId = request.getHeader(TRACE_ID_NAME); - TraceScope traceScope = null; - if (hasText(spanId) && hasText(traceId)) { - - BasicSpanIdentifiers traceInfo = new BasicSpanIdentifiers(traceId, spanId); - // TODO: trace description? - traceScope = trace.startSpan("traceZuulFilter", traceInfo); - } - else { - traceScope = trace.startSpan("traceZuulFilter"); - - } - - context.set("traceScope", traceScope); - - return null; - } -} diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TraceZuulAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TraceZuulAutoConfiguration.java deleted file mode 100644 index 18d542435..000000000 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TraceZuulAutoConfiguration.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.springframework.cloud.sleuth.instrument.zuul; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.cloud.sleuth.Trace; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import com.netflix.zuul.ZuulFilter; - -/** - * @author Spencer Gibb - */ -@Configuration -@ConditionalOnClass(ZuulFilter.class) -@ConditionalOnBean(Trace.class) -public class TraceZuulAutoConfiguration { - - @Bean - public TracePreFilter tracePreFilter(Trace trace) { - return new TracePreFilter(trace); - } - - @Bean - public TracePostFilter tracePostFilter(Trace trace) { - return new TracePostFilter(trace); - } -} diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/slf4j/SleuthSlf4jAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/slf4j/SleuthSlf4jAutoConfiguration.java index f17d0cba9..63cfce7ea 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/slf4j/SleuthSlf4jAutoConfiguration.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/slf4j/SleuthSlf4jAutoConfiguration.java @@ -13,12 +13,8 @@ import org.springframework.context.annotation.Configuration; public class SleuthSlf4jAutoConfiguration { @Bean - public Slf4jSpanStartedListener slf4jSpanStartedListener() { - return new Slf4jSpanStartedListener(); + public Slf4jSpanListener slf4jSpanStartedListener() { + return new Slf4jSpanListener(); } - @Bean - public Slf4jSpanStoppedListener slf4jSpanStoppedListener() { - return new Slf4jSpanStoppedListener(); - } } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/slf4j/Slf4jSpanListener.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/slf4j/Slf4jSpanListener.java new file mode 100644 index 000000000..3a6f6a4fe --- /dev/null +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/slf4j/Slf4jSpanListener.java @@ -0,0 +1,46 @@ +package org.springframework.cloud.sleuth.slf4j; + +import static org.springframework.cloud.sleuth.Trace.SPAN_ID_NAME; +import static org.springframework.cloud.sleuth.Trace.TRACE_ID_NAME; +import lombok.extern.slf4j.Slf4j; + +import org.slf4j.MDC; +import org.springframework.cloud.sleuth.Span; +import org.springframework.cloud.sleuth.Trace; +import org.springframework.cloud.sleuth.event.SpanStartedEvent; +import org.springframework.cloud.sleuth.event.SpanStoppedEvent; +import org.springframework.context.event.EventListener; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; + +/** + * @author Spencer Gibb + */ +@Slf4j +@Order(Ordered.LOWEST_PRECEDENCE) +public class Slf4jSpanListener { + + @EventListener(SpanStartedEvent.class) + public void start(SpanStartedEvent event) { + Span span = event.getSpan(); + MDC.put(Trace.SPAN_ID_NAME, span.getSpanId()); + MDC.put(Trace.TRACE_ID_NAME, span.getTraceId()); + //TODO: what log level? + log.info("Starting span: {}", span); + if (event.getParent()!=null) { + log.info("Starting parent: {}", event.getParent()); + } + } + + @EventListener(SpanStoppedEvent.class) + public void stop(SpanStoppedEvent event) { + //TODO: what should this log level be? + log.info("Stopped span: {}", event.getSpan()); + if (event.getParent()!=null) { + log.info("Stopped parent: {}", event.getParent()); + } + MDC.remove(SPAN_ID_NAME); + MDC.remove(TRACE_ID_NAME); + } + +} diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/slf4j/Slf4jSpanStartedListener.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/slf4j/Slf4jSpanStartedListener.java deleted file mode 100644 index 9106f20fa..000000000 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/slf4j/Slf4jSpanStartedListener.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.springframework.cloud.sleuth.slf4j; - -import lombok.extern.slf4j.Slf4j; - -import org.slf4j.MDC; -import org.springframework.cloud.sleuth.SpanIdentifiers; -import org.springframework.cloud.sleuth.Trace; -import org.springframework.cloud.sleuth.event.SpanStartedEvent; -import org.springframework.context.ApplicationListener; - -/** - * @author Spencer Gibb - */ -@Slf4j -public class Slf4jSpanStartedListener implements ApplicationListener { - - @Override - public void onApplicationEvent(SpanStartedEvent event) { - SpanIdentifiers span = event.getSpan(); - MDC.put(Trace.SPAN_ID_NAME, span.getSpanId()); - MDC.put(Trace.TRACE_ID_NAME, span.getTraceId()); - //TODO: what log level? - log.info("Starting span: {}", span); - } -} diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/slf4j/Slf4jSpanStoppedListener.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/slf4j/Slf4jSpanStoppedListener.java deleted file mode 100644 index b5b12d053..000000000 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/slf4j/Slf4jSpanStoppedListener.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.springframework.cloud.sleuth.slf4j; - -import static org.springframework.cloud.sleuth.Trace.SPAN_ID_NAME; -import static org.springframework.cloud.sleuth.Trace.TRACE_ID_NAME; - -import lombok.extern.slf4j.Slf4j; - -import org.slf4j.MDC; -import org.springframework.cloud.sleuth.event.SpanStoppedEvent; -import org.springframework.context.ApplicationListener; - -/** - * @author Spencer Gibb - */ -@Slf4j -public class Slf4jSpanStoppedListener implements ApplicationListener { - @Override - public void onApplicationEvent(SpanStoppedEvent event) { - //TODO: what should this log level be? - log.info("Received span: {}", event.getSpan()); - MDC.remove(SPAN_ID_NAME); - MDC.remove(TRACE_ID_NAME); - } -} 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 9e7775078..e35844a21 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 @@ -9,7 +9,6 @@ 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.SpanIdentifiers; import org.springframework.cloud.sleuth.Trace; import org.springframework.cloud.sleuth.TraceContextHolder; import org.springframework.cloud.sleuth.TraceScope; @@ -37,16 +36,19 @@ public class DefaultTrace implements Trace { } @Override - public TraceScope startSpan(String name, SpanIdentifiers parent) { + public TraceScope startSpan(String name, Span parent) { if (parent == null) { return startSpan(name); } - SpanIdentifiers currentSpan = getCurrentSpan(); + Span currentSpan = getCurrentSpan(); if (currentSpan != null && !parent.equals(currentSpan)) { error("HTrace client error: thread " + Thread.currentThread().getName() + " tried to start a new Span " + "with parent " + parent.toString() + ", but there is already a " + "currentSpan " + currentSpan); } + if (currentSpan==null) { + TraceContextHolder.setCurrentSpan(parent); + } return continueSpan(createChild(parent, name)); } @@ -64,7 +66,7 @@ public class DefaultTrace implements Trace { return continueSpan(span); } - protected Span createChild(SpanIdentifiers parent, String name) { + protected Span createChild(Span parent, String name) { if (parent == null) { MilliSpan span = MilliSpan.builder().begin(System.currentTimeMillis()).name(name) .traceId(this.idGenerator.create()).spanId(this.idGenerator.create()) diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/DefaultTraceTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/DefaultTraceTests.java index 23dccbc66..efcf56f75 100644 --- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/DefaultTraceTests.java +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/DefaultTraceTests.java @@ -62,15 +62,15 @@ public class DefaultTraceTests { assertThat("spans was wrong size", spans.size(), is(NUM_SPANS)); - SpanIdentifiers root = assertSpan(spans, null, CREATE_SIMPLE_TRACE); - SpanIdentifiers child = assertSpan(spans, root.getSpanId(), IMPORTANT_WORK_1); - SpanIdentifiers grandChild = assertSpan(spans, child.getSpanId(), IMPORTANT_WORK_2); + Span root = assertSpan(spans, null, CREATE_SIMPLE_TRACE); + Span child = assertSpan(spans, root.getSpanId(), IMPORTANT_WORK_1); + Span grandChild = assertSpan(spans, child.getSpanId(), IMPORTANT_WORK_2); List gen4 = findSpans(spans, grandChild.getSpanId()); assertThat("gen4 was non-empty", gen4.isEmpty(), is(true)); } - private SpanIdentifiers assertSpan(List spans, String parentId, String name) { + private Span assertSpan(List spans, String parentId, String name) { List found = findSpans(spans, parentId); assertThat("more than one span with parentId " + parentId, found.size(), is(1)); Span span = found.get(0); 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 a9ddce9ca..e1f610b65 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 @@ -35,9 +35,9 @@ public class SampleApplication { } // Use this for debugging (or if there is no Zipkin collector running on port 9410) - // @Bean - // public SpanCollector spanCollector() { - // return new LoggingSpanCollectorImpl(); - // } + // @Bean + // public SpanCollector spanCollector() { + // return new LoggingSpanCollectorImpl(); + // } } diff --git a/spring-cloud-sleuth-sample/src/main/java/org/springframework/cloud/sleuth/sample/SampleController.java b/spring-cloud-sleuth-sample/src/main/java/org/springframework/cloud/sleuth/sample/SampleController.java index 21e202361..7cd571df5 100644 --- a/spring-cloud-sleuth-sample/src/main/java/org/springframework/cloud/sleuth/sample/SampleController.java +++ b/spring-cloud-sleuth-sample/src/main/java/org/springframework/cloud/sleuth/sample/SampleController.java @@ -8,7 +8,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent; -import org.springframework.cloud.sleuth.SpanIdentifiers; +import org.springframework.cloud.sleuth.Span; import org.springframework.cloud.sleuth.Trace; import org.springframework.cloud.sleuth.TraceContextHolder; import org.springframework.cloud.sleuth.TraceScope; @@ -47,7 +47,7 @@ ApplicationListener { return new Callable() { @Override public String call() throws Exception { - SpanIdentifiers currentSpan = TraceContextHolder.getCurrentSpan(); + Span currentSpan = TraceContextHolder.getCurrentSpan(); return "async hi: "+currentSpan; } }; diff --git a/spring-cloud-sleuth-sample/src/main/resources/application.yml b/spring-cloud-sleuth-sample/src/main/resources/application.yml index 7996c7205..ea69ae529 100644 --- a/spring-cloud-sleuth-sample/src/main/resources/application.yml +++ b/spring-cloud-sleuth-sample/src/main/resources/application.yml @@ -7,7 +7,7 @@ spring: logging: pattern: - console: '%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(${PID:- }){magenta} %clr(---){faint} %clr([trace=%X{Trace-Id:-},span=%X{Span-Id:-}]){yellow} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n%wex' + console: '%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(${PID:- }){magenta} %clr(---){faint} %clr([trace=%X{X-Trace-Id:-},span=%X{X-Span-Id:-}]){yellow} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n%wex' endpoints: health: diff --git a/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/SleuthTracer.java b/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/SleuthTracer.java deleted file mode 100644 index 0aae54d47..000000000 --- a/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/SleuthTracer.java +++ /dev/null @@ -1,207 +0,0 @@ -package org.springframework.cloud.sleuth.zipkin; - -import java.io.UnsupportedEncodingException; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import lombok.extern.apachecommons.CommonsLog; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.web.ServerProperties; -import org.springframework.cloud.sleuth.SpanIdentifiers; -import org.springframework.cloud.sleuth.Span; -import org.springframework.cloud.sleuth.TimelineAnnotation; -import org.springframework.cloud.sleuth.event.SpanStoppedEvent; -import org.springframework.context.event.EventListener; - -import com.github.kristofa.brave.SpanCollector; -import com.twitter.zipkin.gen.Annotation; -import com.twitter.zipkin.gen.AnnotationType; -import com.twitter.zipkin.gen.BinaryAnnotation; -import com.twitter.zipkin.gen.Endpoint; -import com.twitter.zipkin.gen.zipkinCoreConstants; - -/** - * @author Spencer Gibb - */ -@CommonsLog -public class SleuthTracer { - - private SpanCollector spanCollector; - @Value("${spring.application.name:application}") - private String appName; - @Autowired - private ServerProperties serverProperties; - - public SleuthTracer(SpanCollector spanCollector) { - this.spanCollector = spanCollector; - } - - @EventListener - public void start(SpanStoppedEvent event) { - this.spanCollector.collect(convert(event.getSpan())); - } - - /** - * Converts a given Sleuth span to a Zipkin Span. - *

      - *
    • First set the start annotation. [CS, SR], depending whether it is a client service or not. - *
    • Set other id's, etc [TraceId's etc] - *
    • Create binary annotations based on data from HTrace Span object. - *
    • Set the last annotation. [SS, CR] - *
    - */ - public com.twitter.zipkin.gen.Span convert(Span span) { - com.twitter.zipkin.gen.Span zipkinSpan = new com.twitter.zipkin.gen.Span(); - - String serviceName = getServiceName(span); - int address = getAddress(); - Integer port = getPort(); - - Endpoint ep = new Endpoint(address, port.shortValue(), serviceName); - List annotationList = createZipkinAnnotations(span, ep); - List binaryAnnotationList = createZipkinBinaryAnnotations(span, ep); - zipkinSpan.setTrace_id(hash(span.getTraceId())); - if (span.getParents().size() > 0) { - if (span.getParents().size() > 1) { - log.error("zipkin doesn't support spans with multiple parents. Omitting " + - "other parents for " + span); - } - zipkinSpan.setParent_id(hash(span.getParents().get(0))); - } - zipkinSpan.setId(hash(span.getSpanId())); - zipkinSpan.setName(span.getName()); - zipkinSpan.setAnnotations(annotationList); - zipkinSpan.setBinary_annotations(binaryAnnotationList); - return zipkinSpan; - } - - public Integer getPort() { - Integer port; - if (this.serverProperties.getPort() != null) { - port = this.serverProperties.getPort(); - } else { - port = 8080; //TODO: support random port - } - return port; - } - - public int getAddress() { - String address; - if (this.serverProperties.getAddress() != null) { - address = this.serverProperties.getAddress().getHostAddress(); - } else { - address = "127.0.0.1"; //TODO: get address from config - } - return ipAddressToInt(address); - } - - public String getServiceName(SpanIdentifiers span) { - String serviceName; - if (span.getProcessId() != null) { - serviceName = span.getProcessId().toLowerCase(); - } else { - serviceName = this.appName; - } - return serviceName; - } - - - private int ipAddressToInt(final String ip) { - InetAddress inetAddress = null; - try { - inetAddress = InetAddress.getByName(ip); - } catch (final UnknownHostException e) { - throw new IllegalArgumentException(e); - } - return ByteBuffer.wrap(inetAddress.getAddress()).getInt(); - } - - /** - * Add annotations from the sleuth Span. - */ - private List createZipkinAnnotations(Span span, - Endpoint endpoint) { - List annotationList = new ArrayList<>(); - - int duration = (int)(span.getEnd() - span.getBegin()); - - // add first zipkin annotation. - annotationList.add(createZipkinAnnotation(zipkinCoreConstants.CLIENT_SEND, span.getBegin(), 0, endpoint, true)); - annotationList.add(createZipkinAnnotation(zipkinCoreConstants.SERVER_RECV, span.getBegin(), 0, endpoint, true)); - // add sleuth time annotation - for (TimelineAnnotation ta : span.getTimelineAnnotations()) { - annotationList.add(createZipkinAnnotation(ta.getMsg(), ta.getTime(), 0, endpoint, true)); - } - // add last zipkin annotation - annotationList.add(createZipkinAnnotation(zipkinCoreConstants.SERVER_SEND, span.getEnd(), duration, endpoint, false)); - annotationList.add(createZipkinAnnotation(zipkinCoreConstants.CLIENT_RECV, span.getEnd(), duration, endpoint, false)); - return annotationList; - } - - /** - * Creates a list of Annotations that are present in sleuth Span object. - * - * @return list of Annotations that could be added to Zipkin Span. - */ - private List createZipkinBinaryAnnotations(Span span, - Endpoint endpoint) { - List l = new ArrayList<>(); - for (Map.Entry e : span.getKVAnnotations().entrySet()) { - BinaryAnnotation binaryAnn = new BinaryAnnotation(); - binaryAnn.setAnnotation_type(AnnotationType.BYTES); - binaryAnn.setKey(e.getKey()); - try { - binaryAnn.setValue(e.getValue().getBytes("UTF-8")); - } catch (UnsupportedEncodingException ex) { - log.error("Error encoding string as UTF-8", ex); - } - binaryAnn.setHost(endpoint); - l.add(binaryAnn); - } - return l; - } - - /** - * Create an annotation with the correct times and endpoint. - * - * @param value Annotation value - * @param time timestamp will be extracted - * @param endpoint the endpoint this annotation will be associated with. - * @param sendRequest use the first or last timestamp. - */ - private static Annotation createZipkinAnnotation(String value, long time, int duration, - Endpoint endpoint, boolean sendRequest) { - Annotation annotation = new Annotation(); - annotation.setHost(endpoint); - - // Zipkin is in microseconds - if (sendRequest) { - annotation.setTimestamp(time * 1000); - } else { - annotation.setTimestamp(time * 1000); - } - - if (duration > 0) { - annotation.setDuration(duration * 1000); - } - annotation.setValue(value); - return annotation; - } - - private static long hash(String string) { - long h = 1125899906842597L; - int len = string.length(); - - for (int i = 0; i < len; i++) { - h = 31 * h + string.charAt(i); - } - return h; - } - -} 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 caae6c1a6..46394ff16 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 @@ -17,7 +17,6 @@ import com.github.kristofa.brave.ClientTracerConfig; import com.github.kristofa.brave.EndPointSubmitterConfig; import com.github.kristofa.brave.FixedSampleRateTraceFilter; import com.github.kristofa.brave.ServerSpanThreadBinderConfig; -import com.github.kristofa.brave.ServerTracer; import com.github.kristofa.brave.ServerTracerConfig; import com.github.kristofa.brave.SpanCollector; import com.github.kristofa.brave.TraceFilter; @@ -63,16 +62,16 @@ public class ZipkinAutoConfiguration { return new TraceFilters(traceFilters); } - @Bean - @ConditionalOnProperty(value = "spring.cloud.sleuth.zipkin.braveTracer.enabled", matchIfMissing = true) - public ZipkinSpanListener zipkinTrace(ServerTracer serverTracer) { - return new ZipkinSpanListener(serverTracer); - } + // @Bean + // @ConditionalOnProperty(value = "spring.cloud.sleuth.zipkin.braveTracer.enabled", matchIfMissing = true) + // public ZipkinSpanListener zipkinTrace(ServerTracer serverTracer, ClientTracer clientTracer) { + // return new ZipkinSpanListener(serverTracer, clientTracer); + // } @Bean - @ConditionalOnProperty(value = "spring.cloud.sleuth.zipkin.braveTracer.enabled", havingValue = "false") - public SleuthTracer sleuthTracer(SpanCollector spanCollector) { - return new SleuthTracer(spanCollector); + // @ConditionalOnProperty(value = "spring.cloud.sleuth.zipkin.braveTracer.enabled", havingValue = "false") + public ZipkinSpanListener sleuthTracer(SpanCollector spanCollector) { + return new ZipkinSpanListener(spanCollector); } @Configuration 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 582d6ae0a..c61a9046c 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 @@ -1,78 +1,228 @@ package org.springframework.cloud.sleuth.zipkin; -import lombok.Data; +import java.io.UnsupportedEncodingException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + import lombok.extern.apachecommons.CommonsLog; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.cloud.sleuth.Span; -import org.springframework.cloud.sleuth.SpanIdentifiers; +import org.springframework.cloud.sleuth.TimelineAnnotation; +import org.springframework.cloud.sleuth.event.ClientReceivedEvent; +import org.springframework.cloud.sleuth.event.ClientSentEvent; import org.springframework.cloud.sleuth.event.SpanStartedEvent; import org.springframework.cloud.sleuth.event.SpanStoppedEvent; import org.springframework.context.event.EventListener; +import org.springframework.core.annotation.Order; -import com.github.kristofa.brave.ServerTracer; +import com.github.kristofa.brave.SpanCollector; +import com.twitter.zipkin.gen.Annotation; +import com.twitter.zipkin.gen.AnnotationType; +import com.twitter.zipkin.gen.BinaryAnnotation; +import com.twitter.zipkin.gen.Endpoint; +import com.twitter.zipkin.gen.zipkinCoreConstants; /** * @author Spencer Gibb */ @CommonsLog +@Order(0) public class ZipkinSpanListener { - private final ServerTracer serverTracer; + private SpanCollector spanCollector; + @Value("${spring.application.name:application}") + private String appName; + @Autowired + private ServerProperties serverProperties; - public ZipkinSpanListener(ServerTracer serverTracer) { - this.serverTracer = serverTracer; + public ZipkinSpanListener(SpanCollector spanCollector) { + this.spanCollector = spanCollector; } @EventListener public void start(SpanStartedEvent event) { - preTrace(event.getParent(), event.getSpan()); + if (event.getParent()!=null) { + event.getParent().addTimelineAnnotation(zipkinCoreConstants.SERVER_RECV); + } } @EventListener - public void stop(SpanStoppedEvent event) { - postTrace(event.getParent(), event.getSpan()); + public void clientSend(ClientSentEvent event) { + event.getSpan().addTimelineAnnotation(zipkinCoreConstants.CLIENT_SEND); } - 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(hash(span.getTraceId()), - getSpanId(span), getSpanId(parent), spanName); + @EventListener + public void clientReceive(ClientReceivedEvent event) { + event.getSpan().addTimelineAnnotation(zipkinCoreConstants.CLIENT_RECV); + } + + @EventListener + public void start(SpanStoppedEvent event) { + if (event.getParent()!=null) { + event.getParent().addTimelineAnnotation(zipkinCoreConstants.SERVER_SEND); + this.spanCollector.collect(convert(event.getParent())); } - else { - log.debug("Received no span state."); - this.serverTracer.setStateUnknown(spanName); + this.spanCollector.collect(convert(event.getSpan())); + } + + /** + * Converts a given Sleuth span to a Zipkin Span. + *
      + *
    • First set the start annotation. [CS, SR], depending whether it is a client service or not. + *
    • Set other id's, etc [TraceId's etc] + *
    • Create binary annotations based on data from HTrace Span object. + *
    • Set the last annotation. [SS, CR] + *
    + */ + public com.twitter.zipkin.gen.Span convert(Span span) { + com.twitter.zipkin.gen.Span zipkinSpan = new com.twitter.zipkin.gen.Span(); + + String serviceName = getServiceName(span); + int address = getAddress(); + Integer port = getPort(); + + Endpoint ep = new Endpoint(address, port.shortValue(), serviceName); + List annotationList = createZipkinAnnotations(span, ep); + List binaryAnnotationList = createZipkinBinaryAnnotations(span, ep); + zipkinSpan.setTrace_id(hash(span.getTraceId())); + if (span.getParents().size() > 0) { + if (span.getParents().size() > 1) { + log.error("zipkin doesn't support spans with multiple parents. Omitting " + + "other parents for " + span); + } + zipkinSpan.setParent_id(hash(span.getParents().get(0))); } - this.serverTracer.setServerReceived(); + zipkinSpan.setId(hash(span.getSpanId())); + zipkinSpan.setName(span.getName()); + zipkinSpan.setAnnotations(annotationList); + zipkinSpan.setBinary_annotations(binaryAnnotationList); + return zipkinSpan; } - private Long getSpanId(SpanIdentifiers span) { - return span == null ? null : hash(span.getSpanId()); + public Integer getPort() { + Integer port; + if (this.serverProperties.getPort() != null) { + port = this.serverProperties.getPort(); + } else { + port = 8080; //TODO: support random port + } + return port; } - protected String getSpanName(Span context, TraceData traceData) { - return context.getName(); + public int getAddress() { + String address; + if (this.serverProperties.getAddress() != null) { + address = this.serverProperties.getAddress().getHostAddress(); + } else { + address = "127.0.0.1"; //TODO: get address from config + } + return ipAddressToInt(address); } - 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."); + public String getServiceName(Span span) { + String serviceName; + if (span.getProcessId() != null) { + serviceName = span.getProcessId().toLowerCase(); + } else { + serviceName = this.appName; + } + return serviceName; + } + + + private int ipAddressToInt(final String ip) { + InetAddress inetAddress = null; try { - this.serverTracer.setServerSend(); - } - finally { - this.serverTracer.clearCurrentSpan(); + inetAddress = InetAddress.getByName(ip); + } catch (final UnknownHostException e) { + throw new IllegalArgumentException(e); } + return ByteBuffer.wrap(inetAddress.getAddress()).getInt(); } - @Data - private static class TraceData { - private Long traceId; - private Long spanId; - private Long parentSpanId; - private String spanName; + /** + * Add annotations from the sleuth Span. + */ + private List createZipkinAnnotations(Span span, + Endpoint endpoint) { + List annotationList = new ArrayList<>(); + + long srTime = 0, csTime = 0; + // add sleuth time annotation + for (TimelineAnnotation ta : span.getTimelineAnnotations()) { + Annotation zipkinAnnotation = createZipkinAnnotation(ta.getMsg(), ta.getTime(), 0, endpoint, true); + if (zipkinCoreConstants.SERVER_RECV.equals(ta.getMsg())) { + srTime = ta.getTime(); + } + if (zipkinCoreConstants.SERVER_SEND.equals(ta.getMsg()) && srTime!=0) { + zipkinAnnotation.setDuration(new Long(ta.getTime() - srTime).intValue()*1000); + } + if (zipkinCoreConstants.CLIENT_SEND.equals(ta.getMsg())) { + csTime = ta.getTime(); + } + if (zipkinCoreConstants.CLIENT_RECV.equals(ta.getMsg()) && csTime!=0) { + zipkinAnnotation.setDuration(new Long(ta.getTime() - csTime).intValue()*1000); + } + annotationList.add(zipkinAnnotation); + } + return annotationList; + } + + /** + * Creates a list of Annotations that are present in sleuth Span object. + * + * @return list of Annotations that could be added to Zipkin Span. + */ + private List createZipkinBinaryAnnotations(Span span, + Endpoint endpoint) { + List l = new ArrayList<>(); + for (Map.Entry e : span.getKVAnnotations().entrySet()) { + BinaryAnnotation binaryAnn = new BinaryAnnotation(); + binaryAnn.setAnnotation_type(AnnotationType.BYTES); + binaryAnn.setKey(e.getKey()); + try { + binaryAnn.setValue(e.getValue().getBytes("UTF-8")); + } catch (UnsupportedEncodingException ex) { + log.error("Error encoding string as UTF-8", ex); + } + binaryAnn.setHost(endpoint); + l.add(binaryAnn); + } + return l; + } + + /** + * Create an annotation with the correct times and endpoint. + * + * @param value Annotation value + * @param time timestamp will be extracted + * @param endpoint the endpoint this annotation will be associated with. + * @param sendRequest use the first or last timestamp. + */ + private static Annotation createZipkinAnnotation(String value, long time, int duration, + Endpoint endpoint, boolean sendRequest) { + Annotation annotation = new Annotation(); + annotation.setHost(endpoint); + + // Zipkin is in microseconds + if (sendRequest) { + annotation.setTimestamp(time * 1000); + } else { + annotation.setTimestamp(time * 1000); + } + + if (duration > 0) { + annotation.setDuration(duration * 1000); + } + annotation.setValue(value); + return annotation; } private static long hash(String string) {