Merge pull request #7 from dsyer/refactor/collector
Use brave collector and add needed parents/ids
This commit is contained in:
@@ -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<String> parents;
|
||||
private String spanId;
|
||||
private final String spanId;
|
||||
private Map<String, String> kVAnnotations = new LinkedHashMap<>();
|
||||
private String processId;
|
||||
private final String processId;
|
||||
@Singular
|
||||
private List<TimelineAnnotation> 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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,6 +12,40 @@ import java.util.Map;
|
||||
* parents.<p/>
|
||||
*/
|
||||
public interface Span {
|
||||
|
||||
/**
|
||||
* A human-readable name assigned to this span instance.<p/>
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* A pseudo-unique (random) number assigned to this span instance.<p/>
|
||||
* <p/>
|
||||
* 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.<p/>
|
||||
* <p/>
|
||||
* Will never be null.
|
||||
*/
|
||||
String getProcessId();
|
||||
|
||||
/**
|
||||
* Returns the parent IDs of the span.<p/>
|
||||
* <p/>
|
||||
* The collection will be empty if there are no parents.
|
||||
*/
|
||||
List<String> getParents();
|
||||
|
||||
/**
|
||||
* The block has completed, stop the clock
|
||||
*/
|
||||
@@ -38,34 +72,6 @@ public interface Span {
|
||||
*/
|
||||
boolean isRunning();
|
||||
|
||||
/**
|
||||
* Return a textual name of this span.<p/>
|
||||
* <p/>
|
||||
* Will never be null.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* A pseudo-unique (random) number assigned to this span instance.<p/>
|
||||
* <p/>
|
||||
* 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.<p/>
|
||||
* <p/>
|
||||
* The collection will be empty if there are no parents.
|
||||
*/
|
||||
List<String> getParents();
|
||||
|
||||
/**
|
||||
* Add a data annotation associated with this span
|
||||
*/
|
||||
@@ -89,11 +95,4 @@ public interface Span {
|
||||
* Will never be null.
|
||||
*/
|
||||
List<TimelineAnnotation> getTimelineAnnotations();
|
||||
|
||||
/**
|
||||
* Return a unique id for the process from which this Span originated.<p/>
|
||||
* <p/>
|
||||
* Will never be null.
|
||||
*/
|
||||
String getProcessId();
|
||||
}
|
||||
|
||||
@@ -3,71 +3,76 @@ 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:
|
||||
* <ul>
|
||||
* <li>Create a new Span which has this thread's currentSpan as one of its parents.</li>
|
||||
* <li>Set currentSpan to the new Span.</li>
|
||||
* <li>Create a TraceSpan object to manage the new Span.</li>
|
||||
* <li>Create a new Span which has this thread's currentSpan as one of its parents.</li>
|
||||
* <li>Set currentSpan to the new Span.</li>
|
||||
* <li>Create a TraceSpan object to manage the new Span.</li>
|
||||
* </ul>
|
||||
*
|
||||
* Closing a TraceScope does a few things:
|
||||
* <ul>
|
||||
* <li>It closes the span which the scope was managing.</li>
|
||||
* <li>Set currentSpan to the previous currentSpan (which may be null).</li>
|
||||
* <li>It closes the span which the scope was managing.</li>
|
||||
* <li>Set currentSpan to the previous currentSpan (which may be null).</li>
|
||||
* </ul>
|
||||
*/
|
||||
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 new trace scope.
|
||||
* Creates a trace scope wrapping a new span.
|
||||
* <p/>
|
||||
* 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.
|
||||
* <p/>
|
||||
* 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);
|
||||
|
||||
<T> TraceScope startSpan(String name, Sampler<T> s);
|
||||
|
||||
<T> TraceScope startSpan(String name, Sampler<T> 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
|
||||
*/
|
||||
<T> TraceScope startSpan(String name, Sampler<T> sampler, T info);
|
||||
|
||||
/**
|
||||
* Pick up an existing span from another thread.
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
package org.springframework.cloud.sleuth;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@Data
|
||||
public class TraceInfo {
|
||||
private final String traceId;
|
||||
private final String spanId;
|
||||
}
|
||||
@@ -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;
|
||||
@@ -41,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 Span 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;
|
||||
|
||||
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 " +
|
||||
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;
|
||||
@@ -75,13 +74,19 @@ public class TraceScope implements Closeable {
|
||||
this.detached = true;
|
||||
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 " +
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,13 +25,13 @@ public class TraceAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Sampler<?> defaultSampler() {
|
||||
public Sampler<Void> defaultSampler() {
|
||||
return new IsTracingSampler();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Trace trace(Sampler<?> sampler, IdGenerator idGenerator,
|
||||
public Trace trace(Sampler<Void> sampler, IdGenerator idGenerator,
|
||||
ApplicationEventPublisher publisher) {
|
||||
return new DefaultTrace(sampler, idGenerator, publisher);
|
||||
}
|
||||
|
||||
@@ -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 ClientReceivedEvent extends ApplicationEvent {
|
||||
|
||||
private final Span span;
|
||||
|
||||
public ClientReceivedEvent(Object source, Span span) {
|
||||
super(source);
|
||||
this.span = span;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.springframework.cloud.sleuth.event;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Value;
|
||||
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
@@ -9,15 +9,21 @@ import org.springframework.context.ApplicationEvent;
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@Value
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper=false)
|
||||
@SuppressWarnings("serial")
|
||||
public class SpanStartedEvent extends ApplicationEvent {
|
||||
|
||||
private final Span parent;
|
||||
private final Span span;
|
||||
|
||||
public SpanStartedEvent(Object source, Span span) {
|
||||
this(source, null, span);
|
||||
}
|
||||
|
||||
public SpanStartedEvent(Object source, Span parent, Span span) {
|
||||
super(source);
|
||||
this.parent = parent;
|
||||
this.span = span;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.springframework.cloud.sleuth.event;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Value;
|
||||
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
@@ -9,15 +9,21 @@ 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 Span parent;
|
||||
|
||||
public SpanStoppedEvent(Object source, Span span) {
|
||||
this(source, null, span);
|
||||
}
|
||||
|
||||
public SpanStoppedEvent(Object source, Span parent, Span span) {
|
||||
super(source);
|
||||
this.parent = parent;
|
||||
this.span = span;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.springframework.cloud.sleuth.instrument;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Value;
|
||||
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
@@ -12,27 +13,28 @@ import org.springframework.cloud.sleuth.TraceScope;
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@Value
|
||||
@EqualsAndHashCode(callSuper=false)
|
||||
public class TraceCallable<V> extends TraceDelegate<Callable<V>> implements Callable<V> {
|
||||
|
||||
public TraceCallable(Trace trace, Callable<V> delagate) {
|
||||
super(trace, delagate);
|
||||
public TraceCallable(Trace trace, Callable<V> delegate) {
|
||||
super(trace, delegate);
|
||||
}
|
||||
|
||||
public TraceCallable(Trace trace, Callable<V> delagate, Span parent) {
|
||||
super(trace, delagate, parent);
|
||||
public TraceCallable(Trace trace, Callable<V> delegate, Span parent) {
|
||||
super(trace, delegate, parent);
|
||||
}
|
||||
|
||||
public TraceCallable(Trace trace, Callable<V> delagate, Span parent, String name) {
|
||||
super(trace, delagate, parent, name);
|
||||
public TraceCallable(Trace trace, Callable<V> delegate, Span 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<V> extends TraceDelegate<Callable<V>> implements Call
|
||||
|
||||
}
|
||||
else {
|
||||
return this.delagate.call();
|
||||
return this.getDelegate().call();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package org.springframework.cloud.sleuth.instrument;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceContextHolder;
|
||||
@@ -8,24 +10,25 @@ import org.springframework.cloud.sleuth.TraceScope;
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@Getter
|
||||
public abstract class TraceDelegate<T> {
|
||||
|
||||
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 Span 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, Span parent) {
|
||||
this(trace, delegate, parent, null);
|
||||
}
|
||||
|
||||
public TraceDelegate(Trace trace, T delagate, Span parent, String name) {
|
||||
public TraceDelegate(Trace trace, T delegate, Span 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<T> {
|
||||
}
|
||||
|
||||
protected String getSpanName() {
|
||||
return this.name == null ? Thread.currentThread().getName() : name;
|
||||
return this.name == null ? Thread.currentThread().getName() : this.name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,18 +28,18 @@ public class TraceRunnable extends TraceDelegate<Runnable> implements Runnable {
|
||||
|
||||
@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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,8 +30,9 @@ import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.cloud.sleuth.MilliSpan;
|
||||
import org.springframework.cloud.sleuth.MilliSpan.MilliSpanBuilder;
|
||||
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,19 +76,32 @@ 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 = this.urlPathHelper.getPathWithinApplication(request);
|
||||
String name = "http" + uri;
|
||||
if (hasText(spanId) && hasText(traceId)) {
|
||||
|
||||
TraceInfo traceInfo = new TraceInfo(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());
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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.TraceInfo;
|
||||
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)) {
|
||||
|
||||
TraceInfo traceInfo = new TraceInfo(traceId, spanId);
|
||||
// TODO: trace description?
|
||||
traceScope = trace.startSpan("traceZuulFilter", traceInfo);
|
||||
}
|
||||
else {
|
||||
traceScope = trace.startSpan("traceZuulFilter");
|
||||
|
||||
}
|
||||
|
||||
context.set("traceScope", traceScope);
|
||||
|
||||
return 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);
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,9 @@ import org.springframework.cloud.sleuth.Sampler;
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class AlwaysSampler implements Sampler<Object> {
|
||||
public class AlwaysSampler implements Sampler<Void> {
|
||||
@Override
|
||||
public boolean next(Object info) {
|
||||
public boolean next(Void info) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,10 @@ import org.springframework.cloud.sleuth.TraceContextHolder;
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class IsTracingSampler implements Sampler<Object> {
|
||||
public class IsTracingSampler implements Sampler<Void> {
|
||||
|
||||
@Override
|
||||
public boolean next(Object info) {
|
||||
public boolean next(Void info) {
|
||||
return TraceContextHolder.getCurrentSpan() != null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
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.Trace;
|
||||
import org.springframework.cloud.sleuth.event.SpanStartedEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@Slf4j
|
||||
public class Slf4jSpanStartedListener implements ApplicationListener<SpanStartedEvent> {
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(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);
|
||||
}
|
||||
}
|
||||
@@ -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<SpanStoppedEvent> {
|
||||
@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);
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,6 @@ import org.springframework.cloud.sleuth.Sampler;
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceContextHolder;
|
||||
import org.springframework.cloud.sleuth.TraceInfo;
|
||||
import org.springframework.cloud.sleuth.TraceScope;
|
||||
import org.springframework.cloud.sleuth.event.SpanStartedEvent;
|
||||
import org.springframework.cloud.sleuth.instrument.TraceCallable;
|
||||
@@ -23,102 +22,73 @@ import org.springframework.context.ApplicationEventPublisher;
|
||||
*/
|
||||
public class DefaultTrace implements Trace {
|
||||
|
||||
private final Sampler<?> defaultSampler;
|
||||
private final Sampler<Void> defaultSampler;
|
||||
|
||||
private final IdGenerator idGenerator;
|
||||
|
||||
private final ApplicationEventPublisher publisher;
|
||||
|
||||
public DefaultTrace(Sampler<?> defaultSampler, IdGenerator idGenerator,
|
||||
public DefaultTrace(Sampler<Void> defaultSampler, IdGenerator idGenerator,
|
||||
ApplicationEventPublisher publisher) {
|
||||
this.defaultSampler = defaultSampler;
|
||||
this.idGenerator = idGenerator;
|
||||
this.publisher = publisher;
|
||||
}
|
||||
|
||||
@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) {
|
||||
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);
|
||||
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));
|
||||
if (currentSpan==null) {
|
||||
TraceContextHolder.setCurrentSpan(parent);
|
||||
}
|
||||
return continueSpan(createChild(parent, name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> TraceScope startSpan(String name, Sampler<T> s) {
|
||||
return startSpan(name, s, null);
|
||||
public TraceScope startSpan(String name) {
|
||||
return this.startSpan(name, this.defaultSampler, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> TraceScope startSpan(String name, Sampler<T> s, T info) {
|
||||
Span span = null;
|
||||
if (TraceContextHolder.isTracing() || s.next(info)) {
|
||||
span = createNew(name);
|
||||
}
|
||||
return doStart(span);
|
||||
}
|
||||
|
||||
protected Span createNew(String name) {
|
||||
Span parent = getCurrentSpan();
|
||||
if (parent == null) {
|
||||
return MilliSpan.builder()
|
||||
.begin(System.currentTimeMillis())
|
||||
.name(name)
|
||||
.traceId(this.idGenerator.create())
|
||||
.spanId(this.idGenerator.create())
|
||||
.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) {
|
||||
if (span != null) {
|
||||
this.publisher.publishEvent(new SpanStartedEvent(this, span));
|
||||
span = createChild(getCurrentSpan(), name);
|
||||
}
|
||||
return continueSpan(span);
|
||||
}
|
||||
|
||||
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())
|
||||
.build();
|
||||
this.publisher.publishEvent(new SpanStartedEvent(this, span));
|
||||
return span;
|
||||
}
|
||||
else {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@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 +114,8 @@ public class DefaultTrace implements Trace {
|
||||
@Override
|
||||
public <V> Callable<V> wrap(Callable<V> callable) {
|
||||
if (TraceContextHolder.isTracing()) {
|
||||
return new TraceCallable<>(this, callable, TraceContextHolder.getCurrentSpan());
|
||||
return new TraceCallable<>(this, callable,
|
||||
TraceContextHolder.getCurrentSpan());
|
||||
}
|
||||
return callable;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -36,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();
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ ApplicationListener<EmbeddedServletContainerInitializedEvent> {
|
||||
@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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -1,206 +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.Span;
|
||||
import org.springframework.cloud.sleuth.TimelineAnnotation;
|
||||
|
||||
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;
|
||||
import org.springframework.cloud.sleuth.event.SpanStoppedEvent;
|
||||
import org.springframework.context.event.EventListener;
|
||||
|
||||
/**
|
||||
* @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 HTrace span to a Zipkin Span.
|
||||
* <ul>
|
||||
* <li>First set the start annotation. [CS, SR], depending whether it is a client service or not.
|
||||
* <li>Set other id's, etc [TraceId's etc]
|
||||
* <li>Create binary annotations based on data from HTrace Span object.
|
||||
* <li>Set the last annotation. [SS, CR]
|
||||
* </ul>
|
||||
*/
|
||||
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<Annotation> annotationList = createZipkinAnnotations(span, ep);
|
||||
List<BinaryAnnotation> 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 (serverProperties.getPort() != null) {
|
||||
port = serverProperties.getPort();
|
||||
} else {
|
||||
port = 8080; //TODO: support random port
|
||||
}
|
||||
return port;
|
||||
}
|
||||
|
||||
public int getAddress() {
|
||||
String address;
|
||||
if (serverProperties.getAddress() != null) {
|
||||
address = serverProperties.getAddress().getHostAddress();
|
||||
} else {
|
||||
address = "127.0.0.1"; //TODO: get address from config
|
||||
}
|
||||
return ipAddressToInt(address);
|
||||
}
|
||||
|
||||
public String getServiceName(Span span) {
|
||||
String serviceName;
|
||||
if (span.getProcessId() != null) {
|
||||
serviceName = span.getProcessId().toLowerCase();
|
||||
} else {
|
||||
serviceName = 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<Annotation> createZipkinAnnotations(Span span,
|
||||
Endpoint ep) {
|
||||
List<Annotation> 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));
|
||||
// add sleuth time annotation
|
||||
for (TimelineAnnotation ta : span.getTimelineAnnotations()) {
|
||||
annotationList.add(createZipkinAnnotation(ta.getMsg(), ta.getTime(), 0, ep, 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));
|
||||
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<BinaryAnnotation> createZipkinBinaryAnnotations(Span span,
|
||||
Endpoint ep) {
|
||||
List<BinaryAnnotation> l = new ArrayList<>();
|
||||
for (Map.Entry<String, String> 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(ep);
|
||||
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 ep the endopint 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) {
|
||||
Annotation annotation = new Annotation();
|
||||
annotation.setHost(ep);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
@@ -41,8 +40,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());
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -1,87 +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.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.getSpan());
|
||||
if (event.getParent()!=null) {
|
||||
event.getParent().addTimelineAnnotation(zipkinCoreConstants.SERVER_RECV);
|
||||
}
|
||||
}
|
||||
|
||||
@EventListener
|
||||
public void clientSend(ClientSentEvent event) {
|
||||
event.getSpan().addTimelineAnnotation(zipkinCoreConstants.CLIENT_SEND);
|
||||
}
|
||||
|
||||
@EventListener
|
||||
public void clientReceive(ClientReceivedEvent event) {
|
||||
event.getSpan().addTimelineAnnotation(zipkinCoreConstants.CLIENT_RECV);
|
||||
}
|
||||
|
||||
@EventListener
|
||||
public void start(SpanStoppedEvent event) {
|
||||
postTrace(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) {
|
||||
|
||||
log.debug("Received span information as part of request.");
|
||||
this.serverTracer.setStateCurrentTrace(traceData.getTraceId(),
|
||||
traceData.getSpanId(), traceData.getParentSpanId(), spanName);
|
||||
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.
|
||||
* <ul>
|
||||
* <li>First set the start annotation. [CS, SR], depending whether it is a client service or not.
|
||||
* <li>Set other id's, etc [TraceId's etc]
|
||||
* <li>Create binary annotations based on data from HTrace Span object.
|
||||
* <li>Set the last annotation. [SS, CR]
|
||||
* </ul>
|
||||
*/
|
||||
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<Annotation> annotationList = createZipkinAnnotations(span, ep);
|
||||
List<BinaryAnnotation> 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;
|
||||
}
|
||||
|
||||
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()));
|
||||
public Integer getPort() {
|
||||
Integer port;
|
||||
if (this.serverProperties.getPort() != null) {
|
||||
port = this.serverProperties.getPort();
|
||||
} else {
|
||||
port = 8080; //TODO: support random port
|
||||
}
|
||||
return trace;
|
||||
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(Span 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.");
|
||||
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<Annotation> createZipkinAnnotations(Span span,
|
||||
Endpoint endpoint) {
|
||||
List<Annotation> 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<BinaryAnnotation> createZipkinBinaryAnnotations(Span span,
|
||||
Endpoint endpoint) {
|
||||
List<BinaryAnnotation> l = new ArrayList<>();
|
||||
for (Map.Entry<String, String> 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) {
|
||||
|
||||
Reference in New Issue
Block a user