Big refactor of sleuth core API
Instrumentation should be able to get by with only 2 interfaces: TraceManager and TraceAccessor (the former is not needed if you aren't starting a new Span). No explicit access to thread locals or manipulation of thread context is required (except locally where necessary). A Span is enclosed by a Trace (actually a view of the complete Trace that would be constructed remotely).
This commit is contained in:
@@ -46,7 +46,7 @@ public class MilliSpan implements Span {
|
||||
private final List<TimelineAnnotation> timelineAnnotations = new ArrayList<>();
|
||||
|
||||
public MilliSpan(long begin, long end, String name, String traceId, List<String> parents, String spanId, boolean remote, String processId) {
|
||||
this.begin = begin;
|
||||
this.begin = begin<=0 ? System.currentTimeMillis() : begin;
|
||||
this.end = end;
|
||||
this.name = name;
|
||||
this.traceId = traceId;
|
||||
|
||||
@@ -18,95 +18,62 @@ package org.springframework.cloud.sleuth;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import lombok.Value;
|
||||
import lombok.experimental.NonFinal;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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>
|
||||
* </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>
|
||||
* </ul>
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public interface Trace {
|
||||
@Value
|
||||
@NonFinal
|
||||
public class Trace {
|
||||
|
||||
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";
|
||||
String NOT_SAMPLED_NAME = "X-Not-Sampled";
|
||||
public static final String NOT_SAMPLED_NAME = "X-Not-Sampled";
|
||||
|
||||
List<String> HEADERS = Arrays.asList(SPAN_ID_NAME, TRACE_ID_NAME,
|
||||
SPAN_NAME_NAME, PARENT_ID_NAME, PROCESS_ID_NAME, NOT_SAMPLED_NAME);
|
||||
public static final String PROCESS_ID_NAME = "X-Process-Id";
|
||||
|
||||
public static final String PARENT_ID_NAME = "X-Parent-Id";
|
||||
|
||||
public static final String TRACE_ID_NAME = "X-Trace-Id";
|
||||
|
||||
public static final String SPAN_NAME_NAME = "X-Span-Name";
|
||||
|
||||
public static final String SPAN_ID_NAME = "X-Span-Id";
|
||||
|
||||
public static final List<String> HEADERS = Arrays.asList(SPAN_ID_NAME, TRACE_ID_NAME,
|
||||
SPAN_NAME_NAME, PARENT_ID_NAME, PROCESS_ID_NAME, NOT_SAMPLED_NAME);
|
||||
|
||||
/**
|
||||
* Creates a trace scope wrapping a new span.
|
||||
* <p/>
|
||||
* 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.
|
||||
* the span for this scope
|
||||
*/
|
||||
TraceScope startSpan(String name);
|
||||
private final Span span;
|
||||
|
||||
/**
|
||||
* 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'.
|
||||
*
|
||||
* @param name The name field for the new span to create.
|
||||
* the trace that was "current" before this trace was entered
|
||||
*/
|
||||
TraceScope startSpan(String name, Span parent);
|
||||
private final Trace savedTrace;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
@NonFinal
|
||||
private boolean detached = false;
|
||||
|
||||
/**
|
||||
* Pick up an existing span from another thread.
|
||||
*/
|
||||
TraceScope continueSpan(Span s);
|
||||
public Trace(Trace saved, Span span) {
|
||||
this.savedTrace = saved;
|
||||
this.span = span;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a data annotation to the current span if tracing is currently on.
|
||||
*/
|
||||
void addAnnotation(String key, String value);
|
||||
public Trace(Span span) {
|
||||
this(null, span);
|
||||
}
|
||||
|
||||
<V> Callable<V> wrap(Callable<V> callable);
|
||||
public void addAnnotation(String key, String value) {
|
||||
if (this.span != null && !this.detached) {
|
||||
this.span.addAnnotation(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
public void detach() {
|
||||
this.detached = true;
|
||||
}
|
||||
|
||||
Runnable wrap(Runnable runnable);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Strategy for accessing the current span.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public interface TraceAccessor {
|
||||
|
||||
Span getCurrentSpan();
|
||||
|
||||
boolean isTracing();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2013-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;
|
||||
|
||||
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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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>
|
||||
* </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>
|
||||
* </ul>
|
||||
*/
|
||||
public interface TraceManager extends TraceAccessor {
|
||||
|
||||
/**
|
||||
* Creates a trace wrapping a new span.
|
||||
* <p/>
|
||||
* 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.
|
||||
*/
|
||||
Trace startSpan(String name);
|
||||
|
||||
/**
|
||||
* 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'.
|
||||
*
|
||||
* @param name The name field for the new span to create.
|
||||
*/
|
||||
Trace startSpan(String name, Span parent);
|
||||
|
||||
/**
|
||||
* 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> Trace startSpan(String name, Sampler<T> sampler, T info);
|
||||
|
||||
/**
|
||||
* Pick up an existing span from another thread.
|
||||
*/
|
||||
Trace continueSpan(Span s);
|
||||
|
||||
/**
|
||||
* Adds a data annotation to the current span if tracing is currently on.
|
||||
*/
|
||||
void addAnnotation(String key, String value);
|
||||
|
||||
/**
|
||||
* 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 saved trace if there was one before the trace started (null otherwise)
|
||||
*/
|
||||
Trace detach(Trace trace);
|
||||
|
||||
Trace close(Trace trace);
|
||||
|
||||
<V> Callable<V> wrap(Callable<V> callable);
|
||||
|
||||
Runnable wrap(Runnable runnable);
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-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;
|
||||
|
||||
import java.io.Closeable;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.Value;
|
||||
import lombok.experimental.NonFinal;
|
||||
|
||||
import org.springframework.cloud.sleuth.event.SpanReleasedEvent;
|
||||
import org.springframework.cloud.sleuth.util.ExceptionUtils;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@Value
|
||||
@NonFinal
|
||||
public class TraceScope implements Closeable {
|
||||
|
||||
private final ApplicationEventPublisher publisher;
|
||||
|
||||
/**
|
||||
* the span for this scope
|
||||
*/
|
||||
private final Span span;
|
||||
|
||||
/**
|
||||
* the span that was "current" before this scope was entered
|
||||
*/
|
||||
private final Span savedSpan;
|
||||
|
||||
@NonFinal
|
||||
private boolean detached = false;
|
||||
|
||||
public TraceScope(ApplicationEventPublisher publisher, Span span, Span savedSpan) {
|
||||
this.publisher = publisher;
|
||||
this.span = span;
|
||||
this.savedSpan = savedSpan;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 but "
|
||||
+ "it has already been detached: " + this.span);
|
||||
}
|
||||
this.detached = true;
|
||||
|
||||
Span cur = TraceContextHolder.getCurrentSpan();
|
||||
if (cur != this.span) {
|
||||
ExceptionUtils.error("Tried to detach trace span but "
|
||||
+ "it is not the current span for the '"
|
||||
+ Thread.currentThread().getName() + "' thread: " + this.span
|
||||
+ ". You have " + "probably forgotten to close or detach " + cur);
|
||||
}
|
||||
else {
|
||||
TraceContextHolder.setCurrentSpan(this.savedSpan);
|
||||
}
|
||||
return this.span;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public void close() {
|
||||
if (this.detached) {
|
||||
return;
|
||||
}
|
||||
this.detached = true;
|
||||
Span cur = TraceContextHolder.getCurrentSpan();
|
||||
if (cur != this.span) {
|
||||
ExceptionUtils.error("Tried to close trace span but "
|
||||
+ "it is not the current span for the '"
|
||||
+ Thread.currentThread().getName() + "' thread" + this.span
|
||||
+ ". You have " + "probably forgotten to close or detach " + cur);
|
||||
}
|
||||
else {
|
||||
this.span.stop();
|
||||
if (this.savedSpan != null
|
||||
&& this.span.getParents().contains(this.savedSpan.getSpanId())) {
|
||||
this.publisher.publishEvent(new SpanReleasedEvent(this, this.savedSpan,
|
||||
this.span));
|
||||
}
|
||||
else {
|
||||
this.publisher.publishEvent(new SpanReleasedEvent(this, this.span));
|
||||
}
|
||||
TraceContextHolder.setCurrentSpan(this.savedSpan);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,10 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.sleuth;
|
||||
package org.springframework.cloud.sleuth.autoconfig;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.springframework.cloud.sleuth.IdGenerator;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@@ -19,11 +19,9 @@ package org.springframework.cloud.sleuth.autoconfig;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.sleuth.IdGenerator;
|
||||
import org.springframework.cloud.sleuth.RandomUuidGenerator;
|
||||
import org.springframework.cloud.sleuth.Sampler;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.sampler.IsTracingSampler;
|
||||
import org.springframework.cloud.sleuth.trace.DefaultTrace;
|
||||
import org.springframework.cloud.sleuth.trace.DefaultTraceManager;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -37,20 +35,20 @@ public class TraceAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public IdGenerator idGenerator() {
|
||||
public IdGenerator traceIdGenerator() {
|
||||
return new RandomUuidGenerator();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Sampler<Void> defaultSampler() {
|
||||
public Sampler<Void> defaultTraceSampler() {
|
||||
return new IsTracingSampler();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Trace trace(Sampler<Void> sampler, IdGenerator idGenerator,
|
||||
public DefaultTraceManager traceManager(Sampler<Void> sampler, IdGenerator idGenerator,
|
||||
ApplicationEventPublisher publisher) {
|
||||
return new DefaultTrace(sampler, idGenerator, publisher);
|
||||
return new DefaultTraceManager(sampler, idGenerator, publisher);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,48 +18,36 @@ package org.springframework.cloud.sleuth.instrument;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Value;
|
||||
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceScope;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@Value
|
||||
@EqualsAndHashCode(callSuper=false)
|
||||
public class TraceCallable<V> extends TraceDelegate<Callable<V>> implements Callable<V> {
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class TraceCallable<V> extends TraceDelegate<Callable<V>>implements Callable<V> {
|
||||
|
||||
public TraceCallable(Trace trace, Callable<V> delegate) {
|
||||
super(trace, delegate);
|
||||
public TraceCallable(TraceManager traceManager, Callable<V> delegate) {
|
||||
super(traceManager, delegate);
|
||||
}
|
||||
|
||||
public TraceCallable(Trace trace, Callable<V> delegate, Span parent) {
|
||||
super(trace, delegate, parent);
|
||||
}
|
||||
|
||||
public TraceCallable(Trace trace, Callable<V> delegate, Span parent, String name) {
|
||||
super(trace, delegate, parent, name);
|
||||
public TraceCallable(TraceManager traceManager, Callable<V> delegate, String name) {
|
||||
super(traceManager, delegate, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V call() throws Exception {
|
||||
if (this.getParent() != null) {
|
||||
TraceScope scope = startSpan();
|
||||
|
||||
try {
|
||||
return this.getDelegate().call();
|
||||
}
|
||||
finally {
|
||||
scope.close();
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
Trace trace = startSpan();
|
||||
try {
|
||||
return this.getDelegate().call();
|
||||
}
|
||||
finally {
|
||||
close(trace);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,12 +16,11 @@
|
||||
|
||||
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;
|
||||
import org.springframework.cloud.sleuth.TraceScope;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
@@ -29,28 +28,28 @@ import org.springframework.cloud.sleuth.TraceScope;
|
||||
@Getter
|
||||
public abstract class TraceDelegate<T> {
|
||||
|
||||
private final Trace trace;
|
||||
private final TraceManager traceManager;
|
||||
private final T delegate;
|
||||
private final Span parent;
|
||||
private final String name;
|
||||
private final Span parent;
|
||||
|
||||
public TraceDelegate(Trace trace, T delegate) {
|
||||
this(trace, delegate, TraceContextHolder.getCurrentSpan(), null);
|
||||
public TraceDelegate(TraceManager trace, T delegate) {
|
||||
this(trace, delegate, null);
|
||||
}
|
||||
|
||||
public TraceDelegate(Trace trace, T delegate, Span parent) {
|
||||
this(trace, delegate, parent, null);
|
||||
}
|
||||
|
||||
public TraceDelegate(Trace trace, T delegate, Span parent, String name) {
|
||||
this.trace = trace;
|
||||
public TraceDelegate(TraceManager traceManager, T delegate, String name) {
|
||||
this.traceManager = traceManager;
|
||||
this.delegate = delegate;
|
||||
this.parent = parent;
|
||||
this.name = name;
|
||||
this.parent = traceManager.getCurrentSpan();
|
||||
}
|
||||
|
||||
protected TraceScope startSpan() {
|
||||
return this.trace.startSpan(getSpanName(), this.parent);
|
||||
protected void close(Trace scope) {
|
||||
this.traceManager.close(scope);
|
||||
}
|
||||
|
||||
protected Trace startSpan() {
|
||||
return this.traceManager.startSpan(getSpanName(), this.parent);
|
||||
}
|
||||
|
||||
protected String getSpanName() {
|
||||
|
||||
@@ -16,46 +16,35 @@
|
||||
|
||||
package org.springframework.cloud.sleuth.instrument;
|
||||
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Value;
|
||||
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceScope;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@Value
|
||||
@EqualsAndHashCode(callSuper=false)
|
||||
public class TraceRunnable extends TraceDelegate<Runnable> implements Runnable {
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class TraceRunnable extends TraceDelegate<Runnable>implements Runnable {
|
||||
|
||||
public TraceRunnable(Trace trace, Runnable delagate) {
|
||||
super(trace, delagate);
|
||||
public TraceRunnable(TraceManager traceManager, Runnable delegate) {
|
||||
super(traceManager, delegate);
|
||||
}
|
||||
|
||||
public TraceRunnable(Trace trace, Runnable delagate, Span parent) {
|
||||
super(trace, delagate, parent);
|
||||
}
|
||||
|
||||
public TraceRunnable(Trace trace, Runnable delagate, Span parent, String name) {
|
||||
super(trace, delagate, parent, name);
|
||||
public TraceRunnable(TraceManager traceManager, Runnable delegate, String name) {
|
||||
super(traceManager, delegate, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (this.getParent() != null) {
|
||||
TraceScope scope = startSpan();
|
||||
|
||||
try {
|
||||
this.getDelegate().run();
|
||||
}
|
||||
finally {
|
||||
scope.close();
|
||||
}
|
||||
}
|
||||
else {
|
||||
Trace trace = startSpan();
|
||||
try {
|
||||
this.getDelegate().run();
|
||||
}
|
||||
finally {
|
||||
close(trace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.scheduling.annotation.AsyncConfigurer;
|
||||
@@ -35,7 +35,7 @@ import org.springframework.scheduling.annotation.EnableAsync;
|
||||
@Configuration
|
||||
@ConditionalOnMissingBean(AsyncConfigurer.class)
|
||||
@ConditionalOnProperty(value = "spring.sleuth.async.enabled", matchIfMissing = true)
|
||||
@ConditionalOnBean(Trace.class)
|
||||
@ConditionalOnBean(TraceManager.class)
|
||||
@AutoConfigureAfter(AsyncCustomAutoConfiguration.class)
|
||||
public class AsyncDefaultAutoConfiguration extends AsyncConfigurerSupport {
|
||||
|
||||
|
||||
@@ -18,13 +18,13 @@ package org.springframework.cloud.sleuth.instrument.async;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.cloud.sleuth.instrument.TraceRunnable;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
@@ -32,21 +32,21 @@ import org.springframework.cloud.sleuth.instrument.TraceRunnable;
|
||||
@RequiredArgsConstructor
|
||||
public class LazyTraceExecutor implements Executor {
|
||||
|
||||
private Trace trace;
|
||||
private TraceManager traceManager;
|
||||
private final BeanFactory beanFactory;
|
||||
private final Executor delegate;
|
||||
|
||||
@Override
|
||||
public void execute(Runnable command) {
|
||||
if (this.trace == null) {
|
||||
if (this.traceManager == null) {
|
||||
try {
|
||||
this.trace = this.beanFactory.getBean(Trace.class);
|
||||
this.traceManager = this.beanFactory.getBean(TraceManager.class);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException e) {
|
||||
this.delegate.execute(command);
|
||||
}
|
||||
}
|
||||
this.delegate.execute(new TraceRunnable(this.trace, command));
|
||||
this.delegate.execute(new TraceRunnable(this.traceManager, command));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cloud.sleuth.instrument.concurrent.executor;
|
||||
package org.springframework.cloud.sleuth.instrument.executor;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -24,7 +24,7 @@ import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.cloud.sleuth.instrument.TraceCallable;
|
||||
import org.springframework.cloud.sleuth.instrument.TraceRunnable;
|
||||
/**
|
||||
@@ -34,16 +34,16 @@ import org.springframework.cloud.sleuth.instrument.TraceRunnable;
|
||||
*/
|
||||
public class TraceableExecutorService implements ExecutorService {
|
||||
final ExecutorService delegate;
|
||||
final Trace trace;
|
||||
|
||||
public TraceableExecutorService(final ExecutorService delegate, final Trace trace) {
|
||||
final TraceManager traceManager;
|
||||
|
||||
public TraceableExecutorService(final ExecutorService delegate, final TraceManager traceManager) {
|
||||
this.delegate = delegate;
|
||||
this.trace = trace;
|
||||
this.traceManager = traceManager;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void execute(Runnable command) {
|
||||
final Runnable r = new TraceRunnable(trace, command);
|
||||
final Runnable r = new TraceRunnable(this.traceManager, command);
|
||||
this.delegate.execute(r);
|
||||
}
|
||||
|
||||
@@ -74,19 +74,19 @@ public class TraceableExecutorService implements ExecutorService {
|
||||
|
||||
@Override
|
||||
public <T> Future<T> submit(Callable<T> task) {
|
||||
Callable<T> c = new TraceCallable<>(this.trace, task);
|
||||
Callable<T> c = new TraceCallable<>(this.traceManager, task);
|
||||
return this.delegate.submit(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Future<T> submit(Runnable task, T result) {
|
||||
Runnable r = new TraceRunnable(trace, task);
|
||||
Runnable r = new TraceRunnable(this.traceManager, task);
|
||||
return this.delegate.submit(r, result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<?> submit(Runnable task) {
|
||||
Runnable r = new TraceRunnable(trace, task);
|
||||
Runnable r = new TraceRunnable(this.traceManager, task);
|
||||
return this.delegate.submit(r);
|
||||
}
|
||||
|
||||
@@ -14,14 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.sleuth.instrument.concurrent.executor;
|
||||
package org.springframework.cloud.sleuth.instrument.executor;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.cloud.sleuth.instrument.TraceCallable;
|
||||
import org.springframework.cloud.sleuth.instrument.TraceRunnable;
|
||||
|
||||
@@ -31,38 +31,38 @@ import org.springframework.cloud.sleuth.instrument.TraceRunnable;
|
||||
*
|
||||
*/
|
||||
public class TraceableScheduledExecutorService extends TraceableExecutorService implements ScheduledExecutorService {
|
||||
|
||||
public TraceableScheduledExecutorService(final ScheduledExecutorService delegate, final Trace trace) {
|
||||
super(delegate, trace);
|
||||
|
||||
public TraceableScheduledExecutorService(final ScheduledExecutorService delegate, final TraceManager traceManager) {
|
||||
super(delegate, traceManager);
|
||||
}
|
||||
|
||||
|
||||
private ScheduledExecutorService getScheduledExecutorService() {
|
||||
return (ScheduledExecutorService) this.delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
|
||||
Runnable r = new TraceRunnable(this.trace, command);
|
||||
Runnable r = new TraceRunnable(this.traceManager, command);
|
||||
return getScheduledExecutorService().schedule(r, delay, unit);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
|
||||
Callable<V> c = new TraceCallable<>(this.trace,callable);
|
||||
Callable<V> c = new TraceCallable<>(this.traceManager,callable);
|
||||
return getScheduledExecutorService().schedule(c, delay, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
|
||||
Runnable r = new TraceRunnable(this.trace, command);
|
||||
Runnable r = new TraceRunnable(this.traceManager, command);
|
||||
return getScheduledExecutorService().scheduleAtFixedRate(r, initialDelay, period, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
|
||||
Runnable r = new TraceRunnable(this.trace, command);
|
||||
Runnable r = new TraceRunnable(this.traceManager, command);
|
||||
return getScheduledExecutorService().scheduleWithFixedDelay(r, initialDelay, delay, unit);
|
||||
}
|
||||
|
||||
@@ -14,19 +14,20 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.sleuth.instrument.circuitbreaker;
|
||||
package org.springframework.cloud.sleuth.instrument.hystrix;
|
||||
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
|
||||
import com.netflix.hystrix.HystrixCommand;
|
||||
import com.netflix.hystrix.HystrixCommandGroupKey;
|
||||
import com.netflix.hystrix.HystrixThreadPoolKey;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceScope;
|
||||
|
||||
/**
|
||||
* Abstraction over {@code HystrixCommand} that wraps command execution with Trace setting
|
||||
*
|
||||
* @see HystrixCommand
|
||||
* @see Trace
|
||||
* @see TraceManager
|
||||
*
|
||||
* @author Tomasz Nurkiewicz, 4financeIT
|
||||
* @author Marcin Grzejszczak, 4financeIT
|
||||
@@ -34,40 +35,40 @@ import org.springframework.cloud.sleuth.TraceScope;
|
||||
*/
|
||||
public abstract class TraceCommand<R> extends HystrixCommand<R> {
|
||||
|
||||
private Trace trace;
|
||||
private TraceManager traceManager;
|
||||
|
||||
protected TraceCommand(Trace trace, HystrixCommandGroupKey group) {
|
||||
protected TraceCommand(TraceManager traceManager, HystrixCommandGroupKey group) {
|
||||
super(group);
|
||||
this.trace = trace;
|
||||
this.traceManager = traceManager;
|
||||
}
|
||||
|
||||
protected TraceCommand(Trace trace, HystrixCommandGroupKey group, HystrixThreadPoolKey threadPool) {
|
||||
protected TraceCommand(TraceManager traceManager, HystrixCommandGroupKey group, HystrixThreadPoolKey threadPool) {
|
||||
super(group, threadPool);
|
||||
this.trace = trace;
|
||||
this.traceManager = traceManager;
|
||||
}
|
||||
|
||||
protected TraceCommand(Trace trace, HystrixCommandGroupKey group, int executionIsolationThreadTimeoutInMilliseconds) {
|
||||
protected TraceCommand(TraceManager traceManager, HystrixCommandGroupKey group, int executionIsolationThreadTimeoutInMilliseconds) {
|
||||
super(group, executionIsolationThreadTimeoutInMilliseconds);
|
||||
this.trace = trace;
|
||||
this.traceManager = traceManager;
|
||||
}
|
||||
|
||||
protected TraceCommand(Trace trace, HystrixCommandGroupKey group, HystrixThreadPoolKey threadPool, int executionIsolationThreadTimeoutInMilliseconds) {
|
||||
protected TraceCommand(TraceManager traceManager, HystrixCommandGroupKey group, HystrixThreadPoolKey threadPool, int executionIsolationThreadTimeoutInMilliseconds) {
|
||||
super(group, threadPool, executionIsolationThreadTimeoutInMilliseconds);
|
||||
this.trace = trace;
|
||||
this.traceManager = traceManager;
|
||||
}
|
||||
|
||||
protected TraceCommand(Trace trace, Setter setter) {
|
||||
protected TraceCommand(TraceManager traceManager, Setter setter) {
|
||||
super(setter);
|
||||
this.trace = trace;
|
||||
this.traceManager = traceManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected R run() throws Exception {
|
||||
TraceScope scope = trace.startSpan(getCommandKey().name());
|
||||
Trace trace = this.traceManager.startSpan(getCommandKey().name());
|
||||
try {
|
||||
return doRun();
|
||||
} finally {
|
||||
scope.close();
|
||||
this.traceManager.close(trace);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,19 +16,12 @@
|
||||
|
||||
package org.springframework.cloud.sleuth.instrument.integration;
|
||||
|
||||
import static org.springframework.cloud.sleuth.Trace.HEADERS;
|
||||
import static org.springframework.cloud.sleuth.Trace.NOT_SAMPLED_NAME;
|
||||
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 java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.messaging.Message;
|
||||
|
||||
@@ -40,9 +33,9 @@ public class SpanMessageHeaders {
|
||||
|
||||
public static Message<?> addSpanHeaders(Message<?> message, Span span) {
|
||||
if (span == null) {
|
||||
if (!message.getHeaders().containsKey(NOT_SAMPLED_NAME)) {
|
||||
if (!message.getHeaders().containsKey(Trace.NOT_SAMPLED_NAME)) {
|
||||
return MessageBuilder.fromMessage(message)
|
||||
.setHeader(NOT_SAMPLED_NAME, "").build();
|
||||
.setHeader(Trace.NOT_SAMPLED_NAME, "").build();
|
||||
}
|
||||
return message;
|
||||
}
|
||||
@@ -50,17 +43,17 @@ public class SpanMessageHeaders {
|
||||
addAnnotations(message, span);
|
||||
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
addHeader(headers, TRACE_ID_NAME, span.getTraceId());
|
||||
addHeader(headers, SPAN_ID_NAME, span.getSpanId());
|
||||
addHeader(headers, PARENT_ID_NAME, getFirst(span.getParents()));
|
||||
addHeader(headers, SPAN_NAME_NAME, span.getName());
|
||||
addHeader(headers, PROCESS_ID_NAME, span.getProcessId());
|
||||
addHeader(headers, Trace.TRACE_ID_NAME, span.getTraceId());
|
||||
addHeader(headers, Trace.SPAN_ID_NAME, span.getSpanId());
|
||||
addHeader(headers, Trace.PARENT_ID_NAME, getFirst(span.getParents()));
|
||||
addHeader(headers, Trace.SPAN_NAME_NAME, span.getName());
|
||||
addHeader(headers, Trace.PROCESS_ID_NAME, span.getProcessId());
|
||||
return MessageBuilder.fromMessage(message).copyHeaders(headers).build();
|
||||
}
|
||||
|
||||
public static void addAnnotations(Message<?> message, Span span) {
|
||||
for ( Map.Entry<String, Object> entry : message.getHeaders().entrySet()) {
|
||||
if (!HEADERS.contains(entry.getKey())) { //filter out trace headers
|
||||
if (!Trace.HEADERS.contains(entry.getKey())) { //filter out trace headers
|
||||
String key = "/messaging/headers/" + entry.getKey().toLowerCase();
|
||||
String value = null;
|
||||
if (entry.getValue() != null) {
|
||||
|
||||
@@ -16,20 +16,12 @@
|
||||
|
||||
package org.springframework.cloud.sleuth.instrument.integration;
|
||||
|
||||
import static org.springframework.cloud.sleuth.Trace.NOT_SAMPLED_NAME;
|
||||
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;
|
||||
|
||||
import org.springframework.cloud.sleuth.MilliSpan;
|
||||
import org.springframework.cloud.sleuth.MilliSpan.MilliSpanBuilder;
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceContextHolder;
|
||||
import org.springframework.cloud.sleuth.TraceScope;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.integration.channel.AbstractMessageChannel;
|
||||
import org.springframework.integration.context.IntegrationObjectSupport;
|
||||
import org.springframework.messaging.Message;
|
||||
@@ -42,45 +34,38 @@ import org.springframework.messaging.support.ChannelInterceptorAdapter;
|
||||
*/
|
||||
public class TraceChannelInterceptor extends ChannelInterceptorAdapter {
|
||||
|
||||
private ThreadLocal<TraceScope> traceScopeHolder = new ThreadLocal<TraceScope>();
|
||||
private ThreadLocal<Trace> traceManagerScopeHolder = new ThreadLocal<Trace>();
|
||||
|
||||
private ThreadLocal<Span> spanHolder = new ThreadLocal<Span>();
|
||||
private final TraceManager traceManager;
|
||||
|
||||
private final Trace trace;
|
||||
|
||||
public TraceChannelInterceptor(Trace trace) {
|
||||
this.trace = trace;
|
||||
public TraceChannelInterceptor(TraceManager traceManager) {
|
||||
this.traceManager = traceManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postSend(Message<?> message, MessageChannel channel, boolean sent) {
|
||||
TraceScope traceScope = this.traceScopeHolder.get();
|
||||
if (traceScope != null) {
|
||||
traceScope.close();
|
||||
}
|
||||
this.traceScopeHolder.remove();
|
||||
// TODO: Maybe the TraceScope could handle this
|
||||
TraceContextHolder.setCurrentSpan(this.spanHolder.get());
|
||||
Trace traceManagerScope = this.traceManagerScopeHolder.get();
|
||||
this.traceManager.close(traceManagerScope);
|
||||
this.traceManagerScopeHolder.remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message<?> preSend(Message<?> message, MessageChannel channel) {
|
||||
this.spanHolder.set(TraceContextHolder.getCurrentSpan());
|
||||
if (TraceContextHolder.isTracing()
|
||||
|| message.getHeaders().containsKey(NOT_SAMPLED_NAME)) {
|
||||
if (this.traceManager.isTracing()
|
||||
|| message.getHeaders().containsKey(Trace.NOT_SAMPLED_NAME)) {
|
||||
return SpanMessageHeaders.addSpanHeaders(message,
|
||||
TraceContextHolder.getCurrentSpan());
|
||||
this.traceManager.getCurrentSpan());
|
||||
}
|
||||
String spanId = getHeader(message, SPAN_ID_NAME);
|
||||
String traceId = getHeader(message, TRACE_ID_NAME);
|
||||
String spanId = getHeader(message, Trace.SPAN_ID_NAME);
|
||||
String traceId = getHeader(message, Trace.TRACE_ID_NAME);
|
||||
String name = "message/" + getChannelName(channel);
|
||||
TraceScope traceScope;
|
||||
Trace trace;
|
||||
if (hasText(spanId) && hasText(traceId)) {
|
||||
|
||||
MilliSpanBuilder span = MilliSpan.builder().traceId(traceId).spanId(spanId);
|
||||
String parentId = getHeader(message, PARENT_ID_NAME);
|
||||
String processId = getHeader(message, PROCESS_ID_NAME);
|
||||
String spanName = getHeader(message, SPAN_NAME_NAME);
|
||||
String parentId = getHeader(message, Trace.PARENT_ID_NAME);
|
||||
String processId = getHeader(message, Trace.PROCESS_ID_NAME);
|
||||
String spanName = getHeader(message, Trace.SPAN_NAME_NAME);
|
||||
if (spanName != null) {
|
||||
span.name(spanName);
|
||||
}
|
||||
@@ -92,14 +77,14 @@ public class TraceChannelInterceptor extends ChannelInterceptorAdapter {
|
||||
}
|
||||
span.remote(true);
|
||||
|
||||
// TODO: trace description?
|
||||
traceScope = this.trace.startSpan(name, span.build());
|
||||
// TODO: traceManager description?
|
||||
trace = this.traceManager.startSpan(name, span.build());
|
||||
}
|
||||
else {
|
||||
traceScope = this.trace.startSpan(name);
|
||||
trace = this.traceManager.startSpan(name);
|
||||
}
|
||||
this.traceScopeHolder.set(traceScope);
|
||||
return SpanMessageHeaders.addSpanHeaders(message, traceScope.getSpan());
|
||||
this.traceManagerScopeHolder.set(trace);
|
||||
return SpanMessageHeaders.addSpanHeaders(message, trace.getSpan());
|
||||
}
|
||||
|
||||
private String getChannelName(MessageChannel channel) {
|
||||
|
||||
@@ -16,20 +16,13 @@
|
||||
|
||||
package org.springframework.cloud.sleuth.instrument.integration;
|
||||
|
||||
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.removeCurrentSpan;
|
||||
import static org.springframework.cloud.sleuth.TraceContextHolder.setCurrentSpan;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
@@ -52,18 +45,22 @@ import org.springframework.util.Assert;
|
||||
* @since 1.0
|
||||
*/
|
||||
public class TraceContextPropagationChannelInterceptor extends ChannelInterceptorAdapter
|
||||
implements ExecutorChannelInterceptor {
|
||||
implements ExecutorChannelInterceptor {
|
||||
|
||||
private final static ThreadLocal<Span> ORIGINAL_CONTEXT = new ThreadLocal<>();
|
||||
private final TraceManager traceManager;
|
||||
|
||||
private final static ThreadLocal<Trace> ORIGINAL_CONTEXT = new ThreadLocal<>();
|
||||
|
||||
public TraceContextPropagationChannelInterceptor(TraceManager traceManager) {
|
||||
this.traceManager = traceManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Message<?> preSend(Message<?> message, MessageChannel channel) {
|
||||
if (DirectChannel.class.isAssignableFrom(AopUtils.getTargetClass(channel))) {
|
||||
return message;
|
||||
}
|
||||
|
||||
Span span = getCurrentSpan();
|
||||
|
||||
Span span = this.traceManager.getCurrentSpan();
|
||||
if (span != null) {
|
||||
return new MessageWithSpan(message, span);
|
||||
}
|
||||
@@ -78,7 +75,6 @@ implements ExecutorChannelInterceptor {
|
||||
MessageWithSpan messageWithSpan = (MessageWithSpan) message;
|
||||
Message<?> messageToHandle = messageWithSpan.message;
|
||||
populatePropagatedContext(messageWithSpan.span, messageToHandle, channel);
|
||||
|
||||
return message;
|
||||
}
|
||||
return message;
|
||||
@@ -97,33 +93,21 @@ implements ExecutorChannelInterceptor {
|
||||
}
|
||||
|
||||
private String getParentId(Span span) {
|
||||
return span.getParents() != null && !span.getParents().isEmpty() ? span
|
||||
.getParents().get(0) : null;
|
||||
return span.getParents() != null && !span.getParents().isEmpty()
|
||||
? span.getParents().get(0) : null;
|
||||
}
|
||||
|
||||
protected void populatePropagatedContext(Span span, Message<?> message,
|
||||
MessageChannel channel) {
|
||||
if (span != null) {
|
||||
Span currentContext = getCurrentSpan();
|
||||
ORIGINAL_CONTEXT.set(currentContext);
|
||||
setCurrentSpan(span);
|
||||
ORIGINAL_CONTEXT.set(this.traceManager.continueSpan(span).getSavedTrace());
|
||||
}
|
||||
}
|
||||
|
||||
protected void resetPropagatedContext() {
|
||||
Span originalContext = ORIGINAL_CONTEXT.get();
|
||||
try {
|
||||
if (originalContext == null) {
|
||||
removeCurrentSpan();
|
||||
ORIGINAL_CONTEXT.remove();
|
||||
}
|
||||
else {
|
||||
setCurrentSpan(originalContext);
|
||||
}
|
||||
}
|
||||
catch (Throwable t) {// NOSONAR
|
||||
removeCurrentSpan();
|
||||
}
|
||||
Trace originalContext = ORIGINAL_CONTEXT.get();
|
||||
this.traceManager.detach(originalContext);
|
||||
ORIGINAL_CONTEXT.remove();
|
||||
}
|
||||
|
||||
private class MessageWithSpan implements Message<Object> {
|
||||
@@ -143,16 +127,16 @@ implements ExecutorChannelInterceptor {
|
||||
Map<String, Object> headers = new HashMap<>();
|
||||
headers.putAll(message.getHeaders());
|
||||
|
||||
setHeader(headers, SPAN_ID_NAME, this.span.getSpanId());
|
||||
setHeader(headers, TRACE_ID_NAME, this.span.getTraceId());
|
||||
setHeader(headers, SPAN_NAME_NAME, this.span.getName());
|
||||
String parentId = getParentId(getCurrentSpan());
|
||||
setHeader(headers, Trace.SPAN_ID_NAME, this.span.getSpanId());
|
||||
setHeader(headers, Trace.TRACE_ID_NAME, this.span.getTraceId());
|
||||
setHeader(headers, Trace.SPAN_NAME_NAME, this.span.getName());
|
||||
String parentId = getParentId(span);
|
||||
if (parentId != null) {
|
||||
setHeader(headers, PARENT_ID_NAME, parentId);
|
||||
setHeader(headers, Trace.PARENT_ID_NAME, parentId);
|
||||
}
|
||||
String processId = this.span.getProcessId();
|
||||
if (processId != null) {
|
||||
setHeader(headers, PROCESS_ID_NAME, processId);
|
||||
setHeader(headers, Trace.PROCESS_ID_NAME, processId);
|
||||
}
|
||||
this.messageHeaders = new MessageHeaders(headers);
|
||||
}
|
||||
@@ -175,8 +159,8 @@ implements ExecutorChannelInterceptor {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MessageWithSpan{" + "message=" + this.message + ", span="
|
||||
+ this.span + ", messageHeaders=" + this.messageHeaders + '}';
|
||||
return "MessageWithSpan{" + "message=" + this.message + ", span=" + this.span
|
||||
+ ", messageHeaders=" + this.messageHeaders + '}';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -31,20 +31,21 @@ import org.springframework.integration.config.GlobalChannelInterceptor;
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(GlobalChannelInterceptor.class)
|
||||
@ConditionalOnBean(Trace.class)
|
||||
@ConditionalOnBean(TraceManager.class)
|
||||
@AutoConfigureAfter(TraceAutoConfiguration.class)
|
||||
@ConditionalOnProperty(value = "spring.sleuth.integration.enabled", matchIfMissing = true)
|
||||
public class TraceSpringIntegrationAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@GlobalChannelInterceptor
|
||||
public TraceContextPropagationChannelInterceptor traceContextPropagationChannelInterceptor() {
|
||||
return new TraceContextPropagationChannelInterceptor();
|
||||
public TraceContextPropagationChannelInterceptor traceContextPropagationChannelInterceptor(
|
||||
TraceManager trace) {
|
||||
return new TraceContextPropagationChannelInterceptor(trace);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@GlobalChannelInterceptor
|
||||
public TraceChannelInterceptor traceChannelInterceptor(Trace trace) {
|
||||
public TraceChannelInterceptor traceChannelInterceptor(TraceManager trace) {
|
||||
return new TraceChannelInterceptor(trace);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceScope;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
|
||||
/**
|
||||
@@ -32,24 +32,24 @@ import org.springframework.scheduling.annotation.Scheduled;
|
||||
* @author Marcin Grzejszczak, 4financeIT
|
||||
* @author Spencer Gibb
|
||||
*
|
||||
* @see Trace
|
||||
* @see TraceManager
|
||||
*/
|
||||
@Aspect
|
||||
public class TraceSchedulingAspect {
|
||||
|
||||
private final Trace trace;
|
||||
private final TraceManager trace;
|
||||
|
||||
public TraceSchedulingAspect(Trace trace) {
|
||||
public TraceSchedulingAspect(TraceManager trace) {
|
||||
this.trace = trace;
|
||||
}
|
||||
|
||||
@Around("execution (@org.springframework.scheduling.annotation.Scheduled * *.*(..))")
|
||||
public Object traceBackgroundThread(final ProceedingJoinPoint pjp) throws Throwable {
|
||||
TraceScope scope = this.trace.startSpan(pjp.toShortString());
|
||||
Trace scope = this.trace.startSpan(pjp.toShortString());
|
||||
try {
|
||||
return pjp.proceed();
|
||||
} finally {
|
||||
scope.close();
|
||||
this.trace.close(scope);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -42,13 +42,13 @@ import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
@Configuration
|
||||
@EnableAspectJAutoProxy
|
||||
@ConditionalOnProperty(value = "spring.sleuth.schedule.enabled", matchIfMissing = true)
|
||||
@ConditionalOnBean(Trace.class)
|
||||
@ConditionalOnBean(TraceManager.class)
|
||||
@AutoConfigureAfter(TraceAutoConfiguration.class)
|
||||
public class TraceSchedulingAutoConfiguration {
|
||||
|
||||
@ConditionalOnClass(ProceedingJoinPoint.class)
|
||||
@Bean
|
||||
public TraceSchedulingAspect traceSchedulingAspect(Trace trace) {
|
||||
public TraceSchedulingAspect traceSchedulingAspect(TraceManager trace) {
|
||||
return new TraceSchedulingAspect(trace);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,12 +15,6 @@
|
||||
*/
|
||||
package org.springframework.cloud.sleuth.instrument.web;
|
||||
|
||||
import static org.springframework.cloud.sleuth.Trace.NOT_SAMPLED_NAME;
|
||||
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;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -36,8 +30,7 @@ import org.springframework.cloud.sleuth.MilliSpan;
|
||||
import org.springframework.cloud.sleuth.MilliSpan.MilliSpanBuilder;
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceContextHolder;
|
||||
import org.springframework.cloud.sleuth.TraceScope;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.cloud.sleuth.event.ServerReceivedEvent;
|
||||
import org.springframework.cloud.sleuth.event.ServerSentEvent;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
@@ -53,7 +46,7 @@ import org.springframework.web.util.UrlPathHelper;
|
||||
* {@link Trace#TRACE_ID_NAME} header from either request or response and uses them to
|
||||
* create a new span.
|
||||
*
|
||||
* @see Trace
|
||||
* @see TraceManager
|
||||
*
|
||||
* @author Jakub Nabrdalik, 4financeIT
|
||||
* @author Tomasz Nurkiewicz, 4financeIT
|
||||
@@ -70,19 +63,19 @@ public class TraceFilter extends OncePerRequestFilter implements ApplicationEven
|
||||
public static final Pattern DEFAULT_SKIP_PATTERN = Pattern
|
||||
.compile("/api-docs.*|/autoconfig|/configprops|/dump|/info|/metrics.*|/mappings|/trace|/swagger.*|.*\\.png|.*\\.css|.*\\.js|.*\\.html|/favicon.ico|/hystrix.stream");
|
||||
|
||||
private final Trace trace;
|
||||
private final TraceManager traceManager;
|
||||
private final Pattern skipPattern;
|
||||
private UrlPathHelper urlPathHelper = new UrlPathHelper();
|
||||
|
||||
private ApplicationEventPublisher publisher;
|
||||
|
||||
public TraceFilter(Trace trace) {
|
||||
this.trace = trace;
|
||||
public TraceFilter(TraceManager traceManager) {
|
||||
this.traceManager = traceManager;
|
||||
this.skipPattern = DEFAULT_SKIP_PATTERN;
|
||||
}
|
||||
|
||||
public TraceFilter(Trace trace, Pattern skipPattern) {
|
||||
this.trace = trace;
|
||||
public TraceFilter(TraceManager traceManager, Pattern skipPattern) {
|
||||
this.traceManager = traceManager;
|
||||
this.skipPattern = skipPattern;
|
||||
}
|
||||
|
||||
@@ -98,26 +91,26 @@ public class TraceFilter extends OncePerRequestFilter implements ApplicationEven
|
||||
|
||||
String uri = this.urlPathHelper.getPathWithinApplication(request);
|
||||
boolean skip = this.skipPattern.matcher(uri).matches()
|
||||
|| getHeader(request, response, NOT_SAMPLED_NAME) != null;
|
||||
|| getHeader(request, response, Trace.NOT_SAMPLED_NAME) != null;
|
||||
|
||||
TraceScope traceScope = (TraceScope) request.getAttribute(TRACE_REQUEST_ATTR);
|
||||
if (traceScope != null) {
|
||||
this.trace.continueSpan(traceScope.getSpan());
|
||||
Trace trace = (Trace) request.getAttribute(TRACE_REQUEST_ATTR);
|
||||
if (trace != null) {
|
||||
this.traceManager.continueSpan(trace.getSpan());
|
||||
}
|
||||
else if (skip) {
|
||||
addToResponseIfNotPresent(response, NOT_SAMPLED_NAME, "");
|
||||
addToResponseIfNotPresent(response, Trace.NOT_SAMPLED_NAME, "");
|
||||
}
|
||||
else {
|
||||
String spanId = getHeader(request, response, SPAN_ID_NAME);
|
||||
String traceId = getHeader(request, response, TRACE_ID_NAME);
|
||||
String spanId = getHeader(request, response, Trace.SPAN_ID_NAME);
|
||||
String traceId = getHeader(request, response, Trace.TRACE_ID_NAME);
|
||||
String name = "http" + uri;
|
||||
if (hasText(spanId) && hasText(traceId)) {
|
||||
|
||||
MilliSpanBuilder span = 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);
|
||||
String parentId = getHeader(request, response, Trace.PARENT_ID_NAME);
|
||||
String processId = getHeader(request, response, Trace.PROCESS_ID_NAME);
|
||||
String parentName = getHeader(request, response, Trace.SPAN_NAME_NAME);
|
||||
if (parentName != null) {
|
||||
span.name(parentName);
|
||||
}
|
||||
@@ -131,18 +124,18 @@ public class TraceFilter extends OncePerRequestFilter implements ApplicationEven
|
||||
|
||||
// TODO: trace description?
|
||||
Span parent = span.build();
|
||||
traceScope = this.trace.startSpan(name, parent);
|
||||
publish(new ServerReceivedEvent(this, parent, traceScope.getSpan()));
|
||||
request.setAttribute(TRACE_REQUEST_ATTR, traceScope);
|
||||
trace = this.traceManager.startSpan(name, parent);
|
||||
publish(new ServerReceivedEvent(this, parent, trace.getSpan()));
|
||||
request.setAttribute(TRACE_REQUEST_ATTR, trace);
|
||||
// Send new span id back
|
||||
addToResponseIfNotPresent(response, TRACE_ID_NAME, traceScope.getSpan()
|
||||
addToResponseIfNotPresent(response, Trace.TRACE_ID_NAME, trace.getSpan()
|
||||
.getTraceId());
|
||||
addToResponseIfNotPresent(response, SPAN_ID_NAME, traceScope.getSpan()
|
||||
addToResponseIfNotPresent(response, Trace.SPAN_ID_NAME, trace.getSpan()
|
||||
.getSpanId());
|
||||
}
|
||||
else {
|
||||
traceScope = this.trace.startSpan(name);
|
||||
request.setAttribute(TRACE_REQUEST_ATTR, traceScope);
|
||||
trace = this.traceManager.startSpan(name);
|
||||
request.setAttribute(TRACE_REQUEST_ATTR, trace);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,12 +150,14 @@ public class TraceFilter extends OncePerRequestFilter implements ApplicationEven
|
||||
// TODO: how to deal with response annotations and async?
|
||||
return;
|
||||
}
|
||||
if (traceScope != null) {
|
||||
if (trace != null) {
|
||||
addResponseAnnotations(response);
|
||||
publish(new ServerSentEvent(this, traceScope.getSavedSpan(), traceScope.getSpan()));
|
||||
traceScope.close();
|
||||
if (trace.getSavedTrace()!=null) {
|
||||
publish(new ServerSentEvent(this, trace.getSavedTrace().getSpan(), trace.getSpan()));
|
||||
}
|
||||
// Double close to clean up the parent (remote span as well)
|
||||
this.traceManager.close(this.traceManager.close(trace));
|
||||
}
|
||||
TraceContextHolder.removeCurrentSpan();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,10 +170,10 @@ public class TraceFilter extends OncePerRequestFilter implements ApplicationEven
|
||||
//TODO: move annotation keys to constants
|
||||
protected void addRequestAnnotations(HttpServletRequest request) {
|
||||
String uri = this.urlPathHelper.getPathWithinApplication(request);
|
||||
this.trace.addAnnotation("/http/request/uri", request.getRequestURL()
|
||||
this.traceManager.addAnnotation("/http/request/uri", request.getRequestURL()
|
||||
.toString());
|
||||
this.trace.addAnnotation("/http/request/endpoint", uri);
|
||||
this.trace.addAnnotation("/http/request/method", request.getMethod());
|
||||
this.traceManager.addAnnotation("/http/request/endpoint", uri);
|
||||
this.traceManager.addAnnotation("/http/request/method", request.getMethod());
|
||||
|
||||
Enumeration<String> headerNames = request.getHeaderNames();
|
||||
while (headerNames.hasMoreElements()) {
|
||||
@@ -187,20 +182,20 @@ public class TraceFilter extends OncePerRequestFilter implements ApplicationEven
|
||||
while (values.hasMoreElements()) {
|
||||
String value = values.nextElement();
|
||||
String key = "/http/request/headers/" + name.toLowerCase();
|
||||
this.trace.addAnnotation(key, value);
|
||||
this.traceManager.addAnnotation(key, value);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addResponseAnnotations(HttpServletResponse response) {
|
||||
this.trace.addAnnotation("/http/response/status_code",
|
||||
this.traceManager.addAnnotation("/http/response/status_code",
|
||||
String.valueOf(response.getStatus()));
|
||||
|
||||
for (String name : response.getHeaderNames()) {
|
||||
for (String value : response.getHeaders(name)) {
|
||||
String key = "/http/response/headers/" + name.toLowerCase();
|
||||
this.trace.addAnnotation(key, value);
|
||||
this.traceManager.addAnnotation(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
|
||||
package org.springframework.cloud.sleuth.instrument.web;
|
||||
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceScope;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@@ -31,31 +31,32 @@ public class TraceHandlerInterceptor implements HandlerInterceptor {
|
||||
|
||||
private static final String ATTR_NAME = "__CURRENT_TRACE_HANDLER_TRACE_SCOPE_ATTR___";
|
||||
|
||||
private final Trace trace;
|
||||
private final TraceManager traceManager;
|
||||
|
||||
public TraceHandlerInterceptor(Trace trace) {
|
||||
this.trace = trace;
|
||||
public TraceHandlerInterceptor(TraceManager traceManager) {
|
||||
this.traceManager = traceManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
//TODO: get trace data from request?
|
||||
//TODO: what is the description?
|
||||
TraceScope scope = trace.startSpan("traceHandlerInterceptor");
|
||||
request.setAttribute(ATTR_NAME, scope);
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
|
||||
Object handler) throws Exception {
|
||||
// TODO: get trace data from request?
|
||||
// TODO: what is the description?
|
||||
Trace trace = this.traceManager.startSpan("traceHandlerInterceptor");
|
||||
request.setAttribute(ATTR_NAME, trace);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
|
||||
public void postHandle(HttpServletRequest request, HttpServletResponse response,
|
||||
Object handler, ModelAndView modelAndView) throws Exception {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
|
||||
TraceScope scope = TraceScope.class.cast(request.getAttribute(ATTR_NAME));
|
||||
if (scope != null) {
|
||||
scope.close();
|
||||
}
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
|
||||
Object handler, Exception ex) throws Exception {
|
||||
Trace trace = Trace.class.cast(request.getAttribute(ATTR_NAME));
|
||||
this.traceManager.close(trace);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,19 +18,19 @@ package org.springframework.cloud.sleuth.instrument.web;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import lombok.extern.apachecommons.CommonsLog;
|
||||
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceContextHolder;
|
||||
import org.springframework.cloud.sleuth.TraceAccessor;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.cloud.sleuth.instrument.TraceCallable;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
|
||||
import lombok.extern.apachecommons.CommonsLog;
|
||||
|
||||
/**
|
||||
* Aspect that adds correlation id to
|
||||
* <p/>
|
||||
@@ -47,7 +47,7 @@ import org.springframework.web.client.RestOperations;
|
||||
* @see Controller
|
||||
* @see RestOperations
|
||||
* @see TraceCallable
|
||||
* @see Trace
|
||||
* @see TraceManager
|
||||
*
|
||||
* @author Tomasz Nurkewicz, 4financeIT
|
||||
* @author Marcin Grzejszczak, 4financeIT
|
||||
@@ -58,10 +58,12 @@ import org.springframework.web.client.RestOperations;
|
||||
@CommonsLog
|
||||
public class TraceWebAspect {
|
||||
|
||||
private final Trace trace;
|
||||
private final TraceManager traceManager;
|
||||
private final TraceAccessor accessor;
|
||||
|
||||
public TraceWebAspect(Trace trace) {
|
||||
this.trace = trace;
|
||||
public TraceWebAspect(TraceManager traceManager, TraceAccessor accessor) {
|
||||
this.traceManager = traceManager;
|
||||
this.accessor = accessor;
|
||||
}
|
||||
|
||||
@Pointcut("@within(org.springframework.web.bind.annotation.RestController)")
|
||||
@@ -84,11 +86,10 @@ public class TraceWebAspect {
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object wrapWithCorrelationId(ProceedingJoinPoint pjp) throws Throwable {
|
||||
Callable<Object> callable = (Callable<Object>) pjp.proceed();
|
||||
if (TraceContextHolder.isTracing()) {
|
||||
if (this.accessor.isTracing()) {
|
||||
log.debug("Wrapping callable with span ["
|
||||
+ TraceContextHolder.getCurrentSpan() + "]");
|
||||
|
||||
return new TraceCallable<>(this.trace, callable);
|
||||
+ this.accessor.getCurrentSpan() + "]");
|
||||
return new TraceCallable<>(this.traceManager, callable);
|
||||
}
|
||||
else {
|
||||
return callable;
|
||||
|
||||
@@ -24,7 +24,8 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.context.embedded.FilterRegistrationBean;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceAccessor;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -42,7 +43,7 @@ import org.springframework.util.StringUtils;
|
||||
@Configuration
|
||||
@ConditionalOnProperty(value = "spring.sleuth.web.enabled", matchIfMissing = true)
|
||||
@ConditionalOnWebApplication
|
||||
@ConditionalOnBean(Trace.class)
|
||||
@ConditionalOnBean(TraceManager.class)
|
||||
@AutoConfigureAfter(TraceAutoConfiguration.class)
|
||||
public class TraceWebAutoConfiguration {
|
||||
|
||||
@@ -53,18 +54,21 @@ public class TraceWebAutoConfiguration {
|
||||
private String skipPattern;
|
||||
|
||||
@Autowired
|
||||
private Trace trace;
|
||||
private TraceManager traceManager;
|
||||
|
||||
@Autowired
|
||||
private TraceAccessor accessor;
|
||||
|
||||
@Bean
|
||||
public TraceWebAspect traceWebAspect() {
|
||||
return new TraceWebAspect(this.trace);
|
||||
return new TraceWebAspect(this.traceManager, this.accessor);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean traceWebFilter(ApplicationEventPublisher publisher) {
|
||||
Pattern pattern = StringUtils.hasText(this.skipPattern) ? Pattern.compile(this.skipPattern)
|
||||
: TraceFilter.DEFAULT_SKIP_PATTERN;
|
||||
TraceFilter filter = new TraceFilter(this.trace, pattern);
|
||||
TraceFilter filter = new TraceFilter(this.traceManager, pattern);
|
||||
filter.setApplicationEventPublisher(publisher);
|
||||
return new FilterRegistrationBean(filter);
|
||||
}
|
||||
|
||||
@@ -17,9 +17,7 @@
|
||||
package org.springframework.cloud.sleuth.instrument.web.client;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.springframework.cloud.sleuth.Trace.*;
|
||||
import static org.springframework.cloud.sleuth.TraceContextHolder.getCurrentSpan;
|
||||
import static org.springframework.cloud.sleuth.TraceContextHolder.isTracing;
|
||||
import static org.springframework.cloud.sleuth.trace.TraceContextHolder.isTracing;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
@@ -35,6 +33,8 @@ import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
|
||||
import org.springframework.cloud.netflix.feign.support.ResponseEntityDecoder;
|
||||
import org.springframework.cloud.netflix.feign.support.SpringDecoder;
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceAccessor;
|
||||
import org.springframework.cloud.sleuth.event.ClientReceivedEvent;
|
||||
import org.springframework.cloud.sleuth.event.ClientSentEvent;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
@@ -67,10 +67,13 @@ public class TraceFeignClientAutoConfiguration {
|
||||
@Autowired
|
||||
private ApplicationEventPublisher publisher;
|
||||
|
||||
@Autowired
|
||||
private TraceAccessor accessor;
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public Decoder feignDecoder() {
|
||||
return new ResponseEntityDecoder(new SpringDecoder(messageConverters)) {
|
||||
return new ResponseEntityDecoder(new SpringDecoder(this.messageConverters)) {
|
||||
@Override
|
||||
public Object decode(Response response, Type type) throws IOException, FeignException {
|
||||
try {
|
||||
@@ -93,14 +96,14 @@ public class TraceFeignClientAutoConfiguration {
|
||||
public void apply(RequestTemplate template) {
|
||||
Span span = getCurrentSpan();
|
||||
if (span != null) {
|
||||
template.header(TRACE_ID_NAME, span.getTraceId());
|
||||
setHeader(template, SPAN_NAME_NAME, span.getName());
|
||||
setHeader(template, SPAN_ID_NAME, span.getSpanId());
|
||||
setHeader(template, PARENT_ID_NAME, getParentId(span));
|
||||
setHeader(template, PROCESS_ID_NAME, span.getProcessId());
|
||||
template.header(Trace.TRACE_ID_NAME, span.getTraceId());
|
||||
setHeader(template, Trace.SPAN_NAME_NAME, span.getName());
|
||||
setHeader(template, Trace.SPAN_ID_NAME, span.getSpanId());
|
||||
setHeader(template, Trace.PARENT_ID_NAME, getParentId(span));
|
||||
setHeader(template, Trace.PROCESS_ID_NAME, span.getProcessId());
|
||||
publish(new ClientSentEvent(this, span));
|
||||
} else {
|
||||
setHeader(template, NOT_SAMPLED_NAME, "");
|
||||
setHeader(template, Trace.NOT_SAMPLED_NAME, "");
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -126,12 +129,12 @@ public class TraceFeignClientAutoConfiguration {
|
||||
Map<String, Collection<String>> newHeaders = new HashMap<>();
|
||||
newHeaders.putAll(headers);
|
||||
if (getCurrentSpan() == null) {
|
||||
setHeader(newHeaders, NOT_SAMPLED_NAME, "");
|
||||
setHeader(newHeaders, Trace.NOT_SAMPLED_NAME, "");
|
||||
return newHeaders;
|
||||
}
|
||||
setHeader(newHeaders, TRACE_ID_NAME, getCurrentSpan().getTraceId());
|
||||
setHeader(newHeaders, SPAN_ID_NAME, getCurrentSpan().getSpanId());
|
||||
setHeader(newHeaders, PARENT_ID_NAME, getParentId(getCurrentSpan()));
|
||||
setHeader(newHeaders, Trace.TRACE_ID_NAME, getCurrentSpan().getTraceId());
|
||||
setHeader(newHeaders, Trace.SPAN_ID_NAME, getCurrentSpan().getSpanId());
|
||||
setHeader(newHeaders, Trace.PARENT_ID_NAME, getParentId(getCurrentSpan()));
|
||||
return newHeaders;
|
||||
}
|
||||
|
||||
@@ -140,4 +143,9 @@ public class TraceFeignClientAutoConfiguration {
|
||||
headers.put(name, singletonList(value));
|
||||
}
|
||||
}
|
||||
|
||||
private Span getCurrentSpan() {
|
||||
return this.accessor.getCurrentSpan();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,19 +15,13 @@
|
||||
*/
|
||||
package org.springframework.cloud.sleuth.instrument.web.client;
|
||||
|
||||
import static org.springframework.cloud.sleuth.Trace.NOT_SAMPLED_NAME;
|
||||
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 static org.springframework.cloud.sleuth.trace.TraceContextHolder.isTracing;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceAccessor;
|
||||
import org.springframework.cloud.sleuth.event.ClientReceivedEvent;
|
||||
import org.springframework.cloud.sleuth.event.ClientSentEvent;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
@@ -43,7 +37,7 @@ import org.springframework.http.client.ClientHttpResponse;
|
||||
* and sets them if one or both of them are missing.
|
||||
*
|
||||
* @see org.springframework.web.client.RestTemplate
|
||||
* @see Trace
|
||||
* @see TraceAccessor
|
||||
*
|
||||
* @author Marcin Grzejszczak, 4financeIT
|
||||
* @author Spencer Gibb
|
||||
@@ -53,6 +47,12 @@ ApplicationEventPublisherAware {
|
||||
|
||||
private ApplicationEventPublisher publisher;
|
||||
|
||||
private TraceAccessor accessor;
|
||||
|
||||
public TraceRestTemplateInterceptor(TraceAccessor accessor) {
|
||||
this.accessor = accessor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
|
||||
this.publisher = publisher;
|
||||
@@ -62,14 +62,14 @@ ApplicationEventPublisherAware {
|
||||
public ClientHttpResponse intercept(HttpRequest request, byte[] body,
|
||||
ClientHttpRequestExecution execution) throws IOException {
|
||||
if (getCurrentSpan() == null) {
|
||||
setHeader(request, NOT_SAMPLED_NAME, "");
|
||||
setHeader(request, Trace.NOT_SAMPLED_NAME, "");
|
||||
return execution.execute(request, body);
|
||||
}
|
||||
setHeader(request, SPAN_ID_NAME, getCurrentSpan().getSpanId());
|
||||
setHeader(request, TRACE_ID_NAME, getCurrentSpan().getTraceId());
|
||||
setHeader(request, SPAN_NAME_NAME, getCurrentSpan().getName());
|
||||
setHeader(request, PARENT_ID_NAME, getParentId(getCurrentSpan()));
|
||||
setHeader(request, PROCESS_ID_NAME, getCurrentSpan().getProcessId());
|
||||
setHeader(request, Trace.SPAN_ID_NAME, getCurrentSpan().getSpanId());
|
||||
setHeader(request, Trace.TRACE_ID_NAME, getCurrentSpan().getTraceId());
|
||||
setHeader(request, Trace.SPAN_NAME_NAME, getCurrentSpan().getName());
|
||||
setHeader(request, Trace.PARENT_ID_NAME, getParentId(getCurrentSpan()));
|
||||
setHeader(request, Trace.PROCESS_ID_NAME, getCurrentSpan().getProcessId());
|
||||
publish(new ClientSentEvent(this, getCurrentSpan()));
|
||||
return new TraceHttpResponse(this, execution.execute(request, body));
|
||||
}
|
||||
@@ -98,4 +98,8 @@ ApplicationEventPublisherAware {
|
||||
}
|
||||
}
|
||||
|
||||
private Span getCurrentSpan() {
|
||||
return this.accessor.getCurrentSpan();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceAccessor;
|
||||
import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -41,14 +41,14 @@ import org.springframework.web.client.RestTemplate;
|
||||
@Configuration
|
||||
@ConditionalOnProperty(value = "spring.sleuth.client.enabled", matchIfMissing = true)
|
||||
@ConditionalOnClass(RestTemplate.class)
|
||||
@ConditionalOnBean(Trace.class)
|
||||
@ConditionalOnBean(TraceAccessor.class)
|
||||
@AutoConfigureAfter(TraceAutoConfiguration.class)
|
||||
public class TraceWebClientAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public TraceRestTemplateInterceptor traceRestTemplateInterceptor() {
|
||||
return new TraceRestTemplateInterceptor();
|
||||
public TraceRestTemplateInterceptor traceRestTemplateInterceptor(TraceAccessor accessor) {
|
||||
return new TraceRestTemplateInterceptor(accessor);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
package org.springframework.cloud.sleuth.instrument.zuul;
|
||||
|
||||
import static org.springframework.cloud.sleuth.TraceContextHolder.getCurrentSpan;
|
||||
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.TraceAccessor;
|
||||
import org.springframework.cloud.sleuth.event.ClientReceivedEvent;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
@@ -34,6 +34,12 @@ public class TracePostZuulFilter extends ZuulFilter
|
||||
|
||||
private ApplicationEventPublisher publisher;
|
||||
|
||||
private final TraceAccessor accessor;
|
||||
|
||||
public TracePostZuulFilter(TraceAccessor accessor) {
|
||||
this.accessor = accessor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
|
||||
this.publisher = publisher;
|
||||
@@ -67,4 +73,7 @@ public class TracePostZuulFilter extends ZuulFilter
|
||||
}
|
||||
}
|
||||
|
||||
private Span getCurrentSpan() {
|
||||
return this.accessor.getCurrentSpan();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,18 +16,13 @@
|
||||
|
||||
package org.springframework.cloud.sleuth.instrument.zuul;
|
||||
|
||||
import static org.springframework.cloud.sleuth.Trace.NOT_SAMPLED_NAME;
|
||||
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 static org.springframework.cloud.sleuth.trace.TraceContextHolder.isTracing;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceAccessor;
|
||||
import org.springframework.cloud.sleuth.event.ClientSentEvent;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
@@ -46,6 +41,12 @@ ApplicationEventPublisherAware {
|
||||
|
||||
private ApplicationEventPublisher publisher;
|
||||
|
||||
private final TraceAccessor accessor;
|
||||
|
||||
public TracePreZuulFilter(TraceAccessor accessor) {
|
||||
this.accessor = accessor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
|
||||
this.publisher = publisher;
|
||||
@@ -62,15 +63,15 @@ ApplicationEventPublisherAware {
|
||||
Map<String, String> response = ctx.getZuulRequestHeaders();
|
||||
// N.B. this will only work with the simple host filter (not ribbon) unless you set hystrix.execution.isolation.strategy=SEMAPHORE
|
||||
if (getCurrentSpan() == null) {
|
||||
setHeader(response, NOT_SAMPLED_NAME, "");
|
||||
setHeader(response, Trace.NOT_SAMPLED_NAME, "");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
setHeader(response, SPAN_ID_NAME, getCurrentSpan().getSpanId());
|
||||
setHeader(response, TRACE_ID_NAME, getCurrentSpan().getTraceId());
|
||||
setHeader(response, SPAN_NAME_NAME, getCurrentSpan().getName());
|
||||
setHeader(response, PARENT_ID_NAME, getParentId(getCurrentSpan()));
|
||||
setHeader(response, PROCESS_ID_NAME, getCurrentSpan().getProcessId());
|
||||
setHeader(response, Trace.SPAN_ID_NAME, getCurrentSpan().getSpanId());
|
||||
setHeader(response, Trace.TRACE_ID_NAME, getCurrentSpan().getTraceId());
|
||||
setHeader(response, Trace.SPAN_NAME_NAME, getCurrentSpan().getName());
|
||||
setHeader(response, Trace.PARENT_ID_NAME, getParentId(getCurrentSpan()));
|
||||
setHeader(response, Trace.PROCESS_ID_NAME, getCurrentSpan().getProcessId());
|
||||
// TODO: the client sent event should come from the client not the filter!
|
||||
publish(new ClientSentEvent(this, getCurrentSpan()));
|
||||
}
|
||||
@@ -80,6 +81,10 @@ ApplicationEventPublisherAware {
|
||||
return null;
|
||||
}
|
||||
|
||||
private Span getCurrentSpan() {
|
||||
return this.accessor.getCurrentSpan();
|
||||
}
|
||||
|
||||
private String getParentId(Span span) {
|
||||
return span.getParents() != null && !span.getParents().isEmpty() ? span
|
||||
.getParents().get(0) : null;
|
||||
|
||||
@@ -16,25 +16,18 @@
|
||||
|
||||
package org.springframework.cloud.sleuth.instrument.zuul;
|
||||
|
||||
import static org.springframework.cloud.sleuth.Trace.NOT_SAMPLED_NAME;
|
||||
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 static org.springframework.cloud.sleuth.trace.TraceContextHolder.isTracing;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
|
||||
import org.springframework.cloud.netflix.zuul.filters.route.RestClientRibbonCommand;
|
||||
import org.springframework.cloud.netflix.zuul.filters.route.RestClientRibbonCommandFactory;
|
||||
import org.springframework.cloud.netflix.zuul.filters.route.RibbonCommandContext;
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceAccessor;
|
||||
import org.springframework.cloud.sleuth.event.ClientSentEvent;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
@@ -44,16 +37,22 @@ import org.springframework.util.MultiValueMap;
|
||||
import com.netflix.client.http.HttpRequest;
|
||||
import com.netflix.niws.client.http.RestClient;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class TraceRestClientRibbonCommandFactory extends RestClientRibbonCommandFactory
|
||||
implements ApplicationEventPublisherAware {
|
||||
implements ApplicationEventPublisherAware {
|
||||
|
||||
private ApplicationEventPublisher publisher;
|
||||
|
||||
public TraceRestClientRibbonCommandFactory(SpringClientFactory clientFactory) {
|
||||
private final TraceAccessor accessor;
|
||||
|
||||
public TraceRestClientRibbonCommandFactory(SpringClientFactory clientFactory,
|
||||
TraceAccessor accessor) {
|
||||
super(clientFactory);
|
||||
this.accessor = accessor;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -67,34 +66,45 @@ implements ApplicationEventPublisherAware {
|
||||
public RestClientRibbonCommand create(RibbonCommandContext context) {
|
||||
RestClient restClient = getClientFactory().getClient(context.getServiceId(),
|
||||
RestClient.class);
|
||||
return new TraceRestClientRibbonCommand(
|
||||
context.getServiceId(), restClient, getVerb(context.getVerb()),
|
||||
context.getUri(), context.getRetryable(), context.getHeaders(),
|
||||
context.getParams(), context.getRequestEntity(), this.publisher);
|
||||
return new TraceRestClientRibbonCommand(context.getServiceId(), restClient,
|
||||
getVerb(context.getVerb()), context.getUri(), context.getRetryable(),
|
||||
context.getHeaders(), context.getParams(), context.getRequestEntity(),
|
||||
this.publisher, this.accessor);
|
||||
}
|
||||
|
||||
class TraceRestClientRibbonCommand extends RestClientRibbonCommand {
|
||||
|
||||
private ApplicationEventPublisher publisher;
|
||||
|
||||
private final TraceAccessor accessor;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public TraceRestClientRibbonCommand(String commandKey, RestClient restClient, HttpRequest.Verb verb, String uri, Boolean retryable, MultiValueMap<String, String> headers, MultiValueMap<String, String> params, InputStream requestEntity, ApplicationEventPublisher publisher) throws URISyntaxException {
|
||||
super(commandKey, restClient, verb, uri, retryable, headers, params, requestEntity);
|
||||
public TraceRestClientRibbonCommand(String commandKey, RestClient restClient,
|
||||
HttpRequest.Verb verb, String uri, Boolean retryable,
|
||||
MultiValueMap<String, String> headers,
|
||||
MultiValueMap<String, String> params, InputStream requestEntity,
|
||||
ApplicationEventPublisher publisher, TraceAccessor accessor)
|
||||
throws URISyntaxException {
|
||||
super(commandKey, restClient, verb, uri, retryable, headers, params,
|
||||
requestEntity);
|
||||
this.publisher = publisher;
|
||||
this.accessor = accessor;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void customizeRequest(HttpRequest.Builder requestBuilder) {
|
||||
if (getCurrentSpan() == null) {
|
||||
setHeader(requestBuilder, NOT_SAMPLED_NAME, "");
|
||||
setHeader(requestBuilder, Trace.NOT_SAMPLED_NAME, "");
|
||||
return;
|
||||
}
|
||||
|
||||
setHeader(requestBuilder, SPAN_ID_NAME, getCurrentSpan().getSpanId());
|
||||
setHeader(requestBuilder, TRACE_ID_NAME, getCurrentSpan().getTraceId());
|
||||
setHeader(requestBuilder, SPAN_NAME_NAME, getCurrentSpan().getName());
|
||||
setHeader(requestBuilder, PARENT_ID_NAME, getParentId(getCurrentSpan()));
|
||||
setHeader(requestBuilder, PROCESS_ID_NAME, getCurrentSpan().getProcessId());
|
||||
setHeader(requestBuilder, Trace.SPAN_ID_NAME, getCurrentSpan().getSpanId());
|
||||
setHeader(requestBuilder, Trace.TRACE_ID_NAME, getCurrentSpan().getTraceId());
|
||||
setHeader(requestBuilder, Trace.SPAN_NAME_NAME, getCurrentSpan().getName());
|
||||
setHeader(requestBuilder, Trace.PARENT_ID_NAME,
|
||||
getParentId(getCurrentSpan()));
|
||||
setHeader(requestBuilder, Trace.PROCESS_ID_NAME,
|
||||
getCurrentSpan().getProcessId());
|
||||
publish(new ClientSentEvent(this, getCurrentSpan()));
|
||||
}
|
||||
|
||||
@@ -105,8 +115,8 @@ implements ApplicationEventPublisherAware {
|
||||
}
|
||||
|
||||
private String getParentId(Span span) {
|
||||
return span.getParents() != null && !span.getParents().isEmpty() ? span
|
||||
.getParents().get(0) : null;
|
||||
return span.getParents() != null && !span.getParents().isEmpty()
|
||||
? span.getParents().get(0) : null;
|
||||
}
|
||||
|
||||
public void setHeader(HttpRequest.Builder builder, String name, String value) {
|
||||
@@ -114,5 +124,10 @@ implements ApplicationEventPublisherAware {
|
||||
builder.header(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
private Span getCurrentSpan() {
|
||||
return this.accessor.getCurrentSpan();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,8 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceAccessor;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -38,25 +39,25 @@ import com.netflix.zuul.ZuulFilter;
|
||||
@ConditionalOnProperty(value = "spring.sleuth.zuul.enabled", matchIfMissing = true)
|
||||
@ConditionalOnWebApplication
|
||||
@ConditionalOnClass(ZuulFilter.class)
|
||||
@ConditionalOnBean(Trace.class)
|
||||
@ConditionalOnBean(TraceManager.class)
|
||||
@AutoConfigureAfter(TraceAutoConfiguration.class)
|
||||
public class TraceZuulAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public TracePreZuulFilter tracePreZuulFilter() {
|
||||
return new TracePreZuulFilter();
|
||||
public TracePreZuulFilter tracePreZuulFilter(TraceAccessor accessor) {
|
||||
return new TracePreZuulFilter(accessor);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TraceRestClientRibbonCommandFactory traceRestClientRibbonCommandFactory(SpringClientFactory factory) {
|
||||
return new TraceRestClientRibbonCommandFactory(factory);
|
||||
public TraceRestClientRibbonCommandFactory traceRestClientRibbonCommandFactory(SpringClientFactory factory, TraceAccessor accessor) {
|
||||
return new TraceRestClientRibbonCommandFactory(factory, accessor);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public TracePostZuulFilter tracePostZuulFilter() {
|
||||
return new TracePostZuulFilter();
|
||||
public TracePostZuulFilter tracePostZuulFilter(TraceAccessor accessor) {
|
||||
return new TracePostZuulFilter(accessor);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -31,7 +31,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnBean(Trace.class)
|
||||
@ConditionalOnBean(TraceManager.class)
|
||||
@AutoConfigureAfter(TraceAutoConfiguration.class)
|
||||
public class SleuthLogAutoConfiguration {
|
||||
|
||||
|
||||
@@ -16,20 +16,18 @@
|
||||
|
||||
package org.springframework.cloud.sleuth.log;
|
||||
|
||||
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.SpanContinuedEvent;
|
||||
import org.springframework.cloud.sleuth.event.SpanAcquiredEvent;
|
||||
import org.springframework.cloud.sleuth.event.SpanContinuedEvent;
|
||||
import org.springframework.cloud.sleuth.event.SpanReleasedEvent;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@@ -69,8 +67,8 @@ public class Slf4jSpanListener {
|
||||
MDC.put(Trace.SPAN_ID_NAME, event.getParent().getSpanId());
|
||||
}
|
||||
else {
|
||||
MDC.remove(SPAN_ID_NAME);
|
||||
MDC.remove(TRACE_ID_NAME);
|
||||
MDC.remove(Trace.SPAN_ID_NAME);
|
||||
MDC.remove(Trace.TRACE_ID_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package org.springframework.cloud.sleuth.sampler;
|
||||
|
||||
import org.springframework.cloud.sleuth.Sampler;
|
||||
import org.springframework.cloud.sleuth.TraceContextHolder;
|
||||
import org.springframework.cloud.sleuth.trace.TraceContextHolder;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
@@ -26,6 +26,6 @@ public class IsTracingSampler implements Sampler<Void> {
|
||||
|
||||
@Override
|
||||
public boolean next(Void info) {
|
||||
return TraceContextHolder.getCurrentSpan() != null;
|
||||
return TraceContextHolder.isTracing();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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.template;
|
||||
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
|
||||
public interface TraceCallback<T> {
|
||||
T doInTrace(Trace traceScope);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.template;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public interface TraceOperations {
|
||||
|
||||
<T> T trace(TraceCallback<T> task);
|
||||
|
||||
}
|
||||
@@ -14,34 +14,34 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.sleuth;
|
||||
package org.springframework.cloud.sleuth.template;
|
||||
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.cloud.sleuth.instrument.TraceDelegate;
|
||||
import org.springframework.cloud.sleuth.trace.TraceContextHolder;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class TraceTemplate {
|
||||
public class TraceTemplate implements TraceOperations {
|
||||
|
||||
public interface TraceCallback<T> {
|
||||
T doInTrace(TraceScope traceScope);
|
||||
}
|
||||
private final TraceManager trace;
|
||||
|
||||
private final Trace trace;
|
||||
|
||||
public TraceTemplate(Trace trace) {
|
||||
public TraceTemplate(TraceManager trace) {
|
||||
this.trace = trace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T trace(final TraceCallback<T> callback) {
|
||||
DelegateCallback<T> delegate = new DelegateCallback<>(this.trace);
|
||||
|
||||
if (delegate.getParent() != null) {
|
||||
TraceScope traceScope = delegate.startSpan();
|
||||
if (TraceContextHolder.isTracing()) {
|
||||
DelegateCallback<T> delegate = new DelegateCallback<>(this.trace);
|
||||
Trace traceScope = delegate.startSpan();
|
||||
try {
|
||||
return callback.doInTrace(traceScope);
|
||||
} finally {
|
||||
traceScope.close();
|
||||
this.trace.close(traceScope);
|
||||
}
|
||||
} else {
|
||||
return callback.doInTrace(null);
|
||||
@@ -50,12 +50,12 @@ public class TraceTemplate {
|
||||
|
||||
class DelegateCallback<T> extends TraceDelegate<TraceCallback<T>> {
|
||||
|
||||
public DelegateCallback(Trace trace) {
|
||||
public DelegateCallback(TraceManager trace) {
|
||||
super(trace, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TraceScope startSpan() {
|
||||
protected Trace startSpan() {
|
||||
return super.startSpan();
|
||||
}
|
||||
|
||||
@@ -22,22 +22,22 @@ import java.util.concurrent.Callable;
|
||||
|
||||
import org.springframework.cloud.sleuth.IdGenerator;
|
||||
import org.springframework.cloud.sleuth.MilliSpan;
|
||||
import org.springframework.cloud.sleuth.NullScope;
|
||||
import org.springframework.cloud.sleuth.Sampler;
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceContextHolder;
|
||||
import org.springframework.cloud.sleuth.TraceScope;
|
||||
import org.springframework.cloud.sleuth.event.SpanContinuedEvent;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.cloud.sleuth.event.SpanAcquiredEvent;
|
||||
import org.springframework.cloud.sleuth.event.SpanContinuedEvent;
|
||||
import org.springframework.cloud.sleuth.event.SpanReleasedEvent;
|
||||
import org.springframework.cloud.sleuth.instrument.TraceCallable;
|
||||
import org.springframework.cloud.sleuth.instrument.TraceRunnable;
|
||||
import org.springframework.cloud.sleuth.util.ExceptionUtils;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class DefaultTrace implements Trace {
|
||||
public class DefaultTraceManager implements TraceManager {
|
||||
|
||||
private final Sampler<Void> defaultSampler;
|
||||
|
||||
@@ -45,7 +45,7 @@ public class DefaultTrace implements Trace {
|
||||
|
||||
private final ApplicationEventPublisher publisher;
|
||||
|
||||
public DefaultTrace(Sampler<Void> defaultSampler, IdGenerator idGenerator,
|
||||
public DefaultTraceManager(Sampler<Void> defaultSampler, IdGenerator idGenerator,
|
||||
ApplicationEventPublisher publisher) {
|
||||
this.defaultSampler = defaultSampler;
|
||||
this.idGenerator = idGenerator;
|
||||
@@ -53,7 +53,7 @@ public class DefaultTrace implements Trace {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceScope startSpan(String name, Span parent) {
|
||||
public Trace startSpan(String name, Span parent) {
|
||||
if (parent == null) {
|
||||
return startSpan(name);
|
||||
}
|
||||
@@ -63,19 +63,16 @@ public class DefaultTrace implements Trace {
|
||||
+ " 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));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceScope startSpan(String name) {
|
||||
public Trace startSpan(String name) {
|
||||
return this.startSpan(name, this.defaultSampler, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> TraceScope startSpan(String name, Sampler<T> s, T info) {
|
||||
public <T> Trace startSpan(String name, Sampler<T> s, T info) {
|
||||
Span span = null;
|
||||
if (TraceContextHolder.isTracing() || s.next(info)) {
|
||||
span = createChild(getCurrentSpan(), name);
|
||||
@@ -83,17 +80,75 @@ public class DefaultTrace implements Trace {
|
||||
return continueSpan(span);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Trace detach(Trace trace) {
|
||||
if (trace == null) {
|
||||
return null;
|
||||
}
|
||||
trace.detach();
|
||||
Span cur = TraceContextHolder.getCurrentSpan();
|
||||
Span span = trace.getSpan();
|
||||
if (cur != span) {
|
||||
ExceptionUtils.error("Tried to detach trace span but "
|
||||
+ "it is not the current span for the '"
|
||||
+ Thread.currentThread().getName() + "' thread: " + span
|
||||
+ ". You have " + "probably forgotten to close or detach " + cur);
|
||||
}
|
||||
else {
|
||||
if (span != NullTrace.INSTANCE) {
|
||||
TraceContextHolder.setCurrentTrace(trace.getSavedTrace());
|
||||
}
|
||||
}
|
||||
return trace.getSavedTrace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Trace close(Trace trace) {
|
||||
if (trace == null) {
|
||||
return null;
|
||||
}
|
||||
Span cur = TraceContextHolder.getCurrentSpan();
|
||||
Span span = trace.getSpan();
|
||||
Trace savedTrace = trace.getSavedTrace();
|
||||
if (cur != span) {
|
||||
ExceptionUtils.error("Tried to close trace span but "
|
||||
+ "it is not the current span for the '"
|
||||
+ Thread.currentThread().getName() + "' thread" + span
|
||||
+ ". You have " + "probably forgotten to close or detach " + cur);
|
||||
}
|
||||
else {
|
||||
if (span != NullTrace.INSTANCE) {
|
||||
span.stop();
|
||||
if (savedTrace != null
|
||||
&& span.getParents().contains(savedTrace.getSpan().getSpanId())) {
|
||||
this.publisher.publishEvent(
|
||||
new SpanReleasedEvent(this, savedTrace.getSpan(), span));
|
||||
TraceContextHolder.setCurrentTrace(savedTrace);
|
||||
}
|
||||
else {
|
||||
this.publisher.publishEvent(new SpanReleasedEvent(this, span));
|
||||
TraceContextHolder.removeCurrentTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
return savedTrace;
|
||||
}
|
||||
|
||||
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();
|
||||
MilliSpan span = MilliSpan.builder().begin(System.currentTimeMillis())
|
||||
.name(name).traceId(this.idGenerator.create())
|
||||
.spanId(this.idGenerator.create()).build();
|
||||
this.publisher.publishEvent(new SpanAcquiredEvent(this, span));
|
||||
return span;
|
||||
}
|
||||
else {
|
||||
MilliSpan span = MilliSpan.builder().begin(System.currentTimeMillis()).name(name)
|
||||
.traceId(parent.getTraceId()).parent(parent.getSpanId())
|
||||
if (TraceContextHolder.getCurrentTrace() == null) {
|
||||
Trace trace = createTrace(null, parent);
|
||||
TraceContextHolder.setCurrentTrace(trace);
|
||||
}
|
||||
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 SpanAcquiredEvent(this, parent, span));
|
||||
@@ -102,20 +157,31 @@ public class DefaultTrace implements Trace {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceScope continueSpan(Span span) {
|
||||
public Trace continueSpan(Span span) {
|
||||
// Return an empty TraceScope that does nothing on close
|
||||
if (span == null)
|
||||
return NullScope.INSTANCE;
|
||||
Span oldSpan = getCurrentSpan();
|
||||
TraceContextHolder.setCurrentSpan(span);
|
||||
if (span == null) {
|
||||
return NullTrace.INSTANCE;
|
||||
}
|
||||
this.publisher.publishEvent(new SpanContinuedEvent(this, span));
|
||||
return new TraceScope(this.publisher, span, oldSpan);
|
||||
Trace trace = createTrace(TraceContextHolder.getCurrentTrace(), span);
|
||||
TraceContextHolder.setCurrentTrace(trace);
|
||||
return trace;
|
||||
}
|
||||
|
||||
protected Span getCurrentSpan() {
|
||||
protected Trace createTrace(Trace trace, Span span) {
|
||||
return new Trace(trace, span);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span getCurrentSpan() {
|
||||
return TraceContextHolder.getCurrentSpan();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTracing() {
|
||||
return TraceContextHolder.isTracing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAnnotation(String key, String value) {
|
||||
Span s = getCurrentSpan();
|
||||
@@ -132,8 +198,7 @@ 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);
|
||||
}
|
||||
return callable;
|
||||
}
|
||||
@@ -146,8 +211,9 @@ public class DefaultTrace implements Trace {
|
||||
@Override
|
||||
public Runnable wrap(Runnable runnable) {
|
||||
if (TraceContextHolder.isTracing()) {
|
||||
return new TraceRunnable(this, runnable, TraceContextHolder.getCurrentSpan());
|
||||
return new TraceRunnable(this, runnable);
|
||||
}
|
||||
return runnable;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,34 +14,26 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.sleuth;
|
||||
package org.springframework.cloud.sleuth.trace;
|
||||
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
/**
|
||||
* Singleton instance representing an empty {@link TraceScope}.
|
||||
*/
|
||||
public final class NullScope extends TraceScope {
|
||||
public final class NullTrace extends Trace {
|
||||
|
||||
public static final TraceScope INSTANCE = new NullScope();
|
||||
/**
|
||||
* Singleton instance representing an empty {@link Trace}.
|
||||
*/
|
||||
public static final Trace INSTANCE = new NullTrace();
|
||||
|
||||
private NullScope() {
|
||||
super(null, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span detach() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
return;
|
||||
private NullTrace() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NullScope";
|
||||
return "NullTrace";
|
||||
}
|
||||
}
|
||||
@@ -14,24 +14,31 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.sleuth;
|
||||
package org.springframework.cloud.sleuth.trace;
|
||||
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.core.NamedThreadLocal;
|
||||
|
||||
import lombok.extern.apachecommons.CommonsLog;
|
||||
|
||||
import org.springframework.core.NamedThreadLocal;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@CommonsLog
|
||||
public class TraceContextHolder {
|
||||
private static final ThreadLocal<Span> currentSpan = new NamedThreadLocal<>("Trace Context");
|
||||
|
||||
public static Span getCurrentSpan() {
|
||||
private static final ThreadLocal<Trace> currentSpan = new NamedThreadLocal<>("Trace Context");
|
||||
|
||||
public static Trace getCurrentTrace() {
|
||||
return currentSpan.get();
|
||||
}
|
||||
|
||||
public static void setCurrentSpan(Span span) {
|
||||
public static Span getCurrentSpan() {
|
||||
return isTracing() ? currentSpan.get().getSpan() : null;
|
||||
}
|
||||
|
||||
public static void setCurrentTrace(Trace span) {
|
||||
// backwards compatibility
|
||||
if (span == null) {
|
||||
currentSpan.remove();
|
||||
@@ -43,7 +50,7 @@ public class TraceContextHolder {
|
||||
currentSpan.set(span);
|
||||
}
|
||||
|
||||
public static void removeCurrentSpan() {
|
||||
public static void removeCurrentTrace() {
|
||||
currentSpan.remove();
|
||||
}
|
||||
|
||||
@@ -29,18 +29,19 @@ import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.cloud.sleuth.autoconfig.RandomUuidGenerator;
|
||||
import org.springframework.cloud.sleuth.event.SpanAcquiredEvent;
|
||||
import org.springframework.cloud.sleuth.event.SpanReleasedEvent;
|
||||
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
|
||||
import org.springframework.cloud.sleuth.sampler.IsTracingSampler;
|
||||
import org.springframework.cloud.sleuth.trace.DefaultTrace;
|
||||
import org.springframework.cloud.sleuth.trace.DefaultTraceManager;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class DefaultTraceTests {
|
||||
public class DefaultTraceManagerTests {
|
||||
|
||||
public static final String CREATE_SIMPLE_TRACE = "createSimpleTrace";
|
||||
public static final String IMPORTANT_WORK_1 = "important work 1";
|
||||
@@ -51,15 +52,15 @@ public class DefaultTraceTests {
|
||||
public void tracingWorks() {
|
||||
ApplicationEventPublisher publisher = mock(ApplicationEventPublisher.class);
|
||||
|
||||
DefaultTrace trace = new DefaultTrace(new IsTracingSampler(),
|
||||
DefaultTraceManager traceManager = new DefaultTraceManager(new IsTracingSampler(),
|
||||
new RandomUuidGenerator(), publisher);
|
||||
|
||||
TraceScope scope = trace.startSpan(CREATE_SIMPLE_TRACE, new AlwaysSampler(), null);
|
||||
Trace scope = traceManager.startSpan(CREATE_SIMPLE_TRACE, new AlwaysSampler(), null);
|
||||
try {
|
||||
importantWork1(trace);
|
||||
importantWork1(traceManager);
|
||||
}
|
||||
finally {
|
||||
scope.close();
|
||||
traceManager.close(scope);
|
||||
}
|
||||
|
||||
verify(publisher, times(NUM_SPANS)).publishEvent(isA(SpanAcquiredEvent.class));
|
||||
@@ -108,22 +109,22 @@ public class DefaultTraceTests {
|
||||
return found;
|
||||
}
|
||||
|
||||
private void importantWork1(Trace trace) {
|
||||
TraceScope cur = trace.startSpan(IMPORTANT_WORK_1);
|
||||
private void importantWork1(TraceManager traceManager) {
|
||||
Trace cur = traceManager.startSpan(IMPORTANT_WORK_1);
|
||||
try {
|
||||
Thread.sleep((long) (50 * Math.random()));
|
||||
importantWork2(trace);
|
||||
importantWork2(traceManager);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
finally {
|
||||
cur.close();
|
||||
traceManager.close(cur);
|
||||
}
|
||||
}
|
||||
|
||||
private void importantWork2(Trace trace) {
|
||||
TraceScope cur = trace.startSpan(IMPORTANT_WORK_2);
|
||||
private void importantWork2(TraceManager traceManager) {
|
||||
Trace cur = traceManager.startSpan(IMPORTANT_WORK_2);
|
||||
try {
|
||||
Thread.sleep((long) (50 * Math.random()));
|
||||
}
|
||||
@@ -131,7 +132,7 @@ public class DefaultTraceTests {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
finally {
|
||||
cur.close();
|
||||
traceManager.close(cur);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.springframework.cloud.sleuth.instrument.concurrent.executor;
|
||||
package org.springframework.cloud.sleuth.instrument.executor;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
@@ -20,53 +20,52 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.cloud.sleuth.RandomUuidGenerator;
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceContextHolder;
|
||||
import org.springframework.cloud.sleuth.TraceScope;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.cloud.sleuth.autoconfig.RandomUuidGenerator;
|
||||
import org.springframework.cloud.sleuth.event.SpanAcquiredEvent;
|
||||
import org.springframework.cloud.sleuth.event.SpanReleasedEvent;
|
||||
import org.springframework.cloud.sleuth.instrument.TraceRunnable;
|
||||
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
|
||||
import org.springframework.cloud.sleuth.trace.DefaultTrace;
|
||||
import org.springframework.cloud.sleuth.trace.DefaultTraceManager;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
|
||||
public class TraceableExecutorServiceTests {
|
||||
private ApplicationEventPublisher publisher;
|
||||
private ExecutorService traceableExecutorService;
|
||||
private Trace trace;
|
||||
private ExecutorService traceManagerableExecutorService;
|
||||
private TraceManager traceManager;
|
||||
private ExecutorService executorService;
|
||||
|
||||
|
||||
private int NUM_SPANS = 11;
|
||||
private int TOTAL_THREADS = 10;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
this.publisher = Mockito.mock(ApplicationEventPublisher.class);
|
||||
this.trace = new DefaultTrace(new AlwaysSampler(), new RandomUuidGenerator(), this.publisher);
|
||||
this.traceManager = new DefaultTraceManager(new AlwaysSampler(), new RandomUuidGenerator(), this.publisher);
|
||||
ExecutorService es = Executors.newFixedThreadPool(3);
|
||||
this.traceableExecutorService = new TraceableExecutorService(es, this.trace);
|
||||
this.traceManagerableExecutorService = new TraceableExecutorService(es, this.traceManager);
|
||||
this.executorService = Executors.newFixedThreadPool(3);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
this.trace = null;
|
||||
this.traceableExecutorService.shutdown();
|
||||
this.traceManager = null;
|
||||
this.traceManagerableExecutorService.shutdown();
|
||||
this.executorService.shutdown();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void test_whenTraceContextOfWorkerThreadIsNotClosed_thenException() {
|
||||
//THis test case ideally should fail but it is not failing because of the
|
||||
// https://github.com/spring-cloud/spring-cloud-sleuth/issues/60 comment two
|
||||
final AtomicInteger counter = new AtomicInteger(0);
|
||||
final CountDownLatch latch = new CountDownLatch(TOTAL_THREADS);
|
||||
TraceScope scope = this.trace.startSpan("PARENT");
|
||||
for (int i = 0; i < TOTAL_THREADS; i++) {
|
||||
traceableExecutorService.execute(new MyRunnable(counter, latch));
|
||||
final CountDownLatch latch = new CountDownLatch(this.TOTAL_THREADS);
|
||||
Trace scope = this.traceManager.startSpan("PARENT");
|
||||
for (int i = 0; i < this.TOTAL_THREADS; i++) {
|
||||
this.traceManagerableExecutorService.execute(new MyRunnable(counter, latch));
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -74,15 +73,15 @@ public class TraceableExecutorServiceTests {
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
scope.close();
|
||||
|
||||
verify(this.publisher, times(NUM_SPANS)).publishEvent(isA(SpanAcquiredEvent.class));
|
||||
verify(publisher, times(NUM_SPANS)).publishEvent(isA(SpanReleasedEvent.class));
|
||||
this.traceManager.close(scope);
|
||||
|
||||
verify(this.publisher, times(this.NUM_SPANS)).publishEvent(isA(SpanAcquiredEvent.class));
|
||||
verify(this.publisher, times(this.NUM_SPANS)).publishEvent(isA(SpanReleasedEvent.class));
|
||||
|
||||
ArgumentCaptor<ApplicationEvent> captor = ArgumentCaptor
|
||||
.forClass(ApplicationEvent.class);
|
||||
verify(publisher, atLeast(NUM_SPANS)).publishEvent(captor.capture());
|
||||
verify(this.publisher, atLeast(this.NUM_SPANS)).publishEvent(captor.capture());
|
||||
|
||||
List<Span> spans = new ArrayList<>();
|
||||
for (ApplicationEvent event : captor.getAllValues()) {
|
||||
@@ -91,17 +90,17 @@ public class TraceableExecutorServiceTests {
|
||||
}
|
||||
}
|
||||
|
||||
assertThat("spans was wrong size", spans.size(), is(NUM_SPANS));
|
||||
assertThat("spans was wrong size", spans.size(), is(this.NUM_SPANS));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void test_whenTraceContextOfWorkerThreadIsClosed_thenNoException() {
|
||||
final AtomicInteger counter = new AtomicInteger(0);
|
||||
final CountDownLatch latch = new CountDownLatch(TOTAL_THREADS);
|
||||
TraceScope scope = this.trace.startSpan("PARENT");
|
||||
for (int i = 0; i < TOTAL_THREADS; i++) {
|
||||
final TraceRunnableAdapter command = new TraceRunnableAdapter(new TraceRunnable(this.trace, new MyRunnable(counter, latch)));
|
||||
executorService.execute(command);
|
||||
final CountDownLatch latch = new CountDownLatch(this.TOTAL_THREADS);
|
||||
Trace scope = this.traceManager.startSpan("PARENT");
|
||||
for (int i = 0; i < this.TOTAL_THREADS; i++) {
|
||||
final Runnable command = new TraceRunnable(this.traceManager, new MyRunnable(counter, latch));
|
||||
this.executorService.execute(command);
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -109,15 +108,15 @@ public class TraceableExecutorServiceTests {
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
scope.close();
|
||||
|
||||
verify(this.publisher, times(NUM_SPANS)).publishEvent(isA(SpanAcquiredEvent.class));
|
||||
verify(publisher, times(NUM_SPANS)).publishEvent(isA(SpanReleasedEvent.class));
|
||||
this.traceManager.close(scope);
|
||||
|
||||
verify(this.publisher, times(this.NUM_SPANS)).publishEvent(isA(SpanAcquiredEvent.class));
|
||||
verify(this.publisher, times(this.NUM_SPANS)).publishEvent(isA(SpanReleasedEvent.class));
|
||||
|
||||
ArgumentCaptor<ApplicationEvent> captor = ArgumentCaptor
|
||||
.forClass(ApplicationEvent.class);
|
||||
verify(publisher, atLeast(NUM_SPANS)).publishEvent(captor.capture());
|
||||
verify(this.publisher, atLeast(this.NUM_SPANS)).publishEvent(captor.capture());
|
||||
|
||||
List<Span> spans = new ArrayList<>();
|
||||
for (ApplicationEvent event : captor.getAllValues()) {
|
||||
@@ -126,36 +125,18 @@ public class TraceableExecutorServiceTests {
|
||||
}
|
||||
}
|
||||
|
||||
assertThat("spans was wrong size", spans.size(), is(NUM_SPANS));
|
||||
}
|
||||
|
||||
class TraceRunnableAdapter implements Runnable {
|
||||
private final Runnable delegate;
|
||||
public TraceRunnableAdapter(final Runnable delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
this.delegate.run();
|
||||
}
|
||||
finally {
|
||||
TraceContextHolder.removeCurrentSpan();
|
||||
}
|
||||
}
|
||||
|
||||
assertThat("spans was wrong size", spans.size(), is(this.NUM_SPANS));
|
||||
}
|
||||
|
||||
class MyRunnable implements Runnable {
|
||||
private final AtomicInteger counter;
|
||||
private final CountDownLatch latch;
|
||||
|
||||
|
||||
MyRunnable(final AtomicInteger counter, final CountDownLatch latch) {
|
||||
this.counter = counter;
|
||||
this.latch = latch;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
@@ -166,12 +147,12 @@ public class TraceableExecutorServiceTests {
|
||||
}
|
||||
}
|
||||
finally {
|
||||
counter.incrementAndGet();
|
||||
latch.countDown();
|
||||
|
||||
this.counter.incrementAndGet();
|
||||
this.latch.countDown();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,9 +18,6 @@ package org.springframework.cloud.sleuth.instrument.integration;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.springframework.cloud.sleuth.Trace.NOT_SAMPLED_NAME;
|
||||
import static org.springframework.cloud.sleuth.Trace.SPAN_ID_NAME;
|
||||
import static org.springframework.cloud.sleuth.Trace.TRACE_ID_NAME;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
@@ -32,10 +29,10 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.IntegrationTest;
|
||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceContextHolder;
|
||||
import org.springframework.cloud.sleuth.TraceScope;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.cloud.sleuth.instrument.integration.TraceChannelInterceptorTests.App;
|
||||
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
|
||||
import org.springframework.cloud.sleuth.trace.TraceContextHolder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
@@ -60,7 +57,7 @@ public class TraceChannelInterceptorTests implements MessageHandler {
|
||||
private DirectChannel channel;
|
||||
|
||||
@Autowired
|
||||
private Trace trace;
|
||||
private TraceManager trace;
|
||||
|
||||
private Message<?> message;
|
||||
|
||||
@@ -76,17 +73,17 @@ public class TraceChannelInterceptorTests implements MessageHandler {
|
||||
|
||||
@After
|
||||
public void close() {
|
||||
TraceContextHolder.removeCurrentSpan();
|
||||
TraceContextHolder.removeCurrentTrace();
|
||||
this.channel.unsubscribe(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoSpanCreation() {
|
||||
this.channel.send(MessageBuilder.withPayload("hi").setHeader(NOT_SAMPLED_NAME, "")
|
||||
this.channel.send(MessageBuilder.withPayload("hi").setHeader(Trace.NOT_SAMPLED_NAME, "")
|
||||
.build());
|
||||
assertNotNull("message was null", this.message);
|
||||
|
||||
String spanId = this.message.getHeaders().get(SPAN_ID_NAME, String.class);
|
||||
String spanId = this.message.getHeaders().get(Trace.SPAN_ID_NAME, String.class);
|
||||
assertNull("spanId was not null", spanId);
|
||||
}
|
||||
|
||||
@@ -95,28 +92,28 @@ public class TraceChannelInterceptorTests implements MessageHandler {
|
||||
this.channel.send(MessageBuilder.withPayload("hi").build());
|
||||
assertNotNull("message was null", this.message);
|
||||
|
||||
String spanId = this.message.getHeaders().get(SPAN_ID_NAME, String.class);
|
||||
String spanId = this.message.getHeaders().get(Trace.SPAN_ID_NAME, String.class);
|
||||
assertNotNull("spanId was null", spanId);
|
||||
|
||||
String traceId = this.message.getHeaders().get(TRACE_ID_NAME, String.class);
|
||||
String traceId = this.message.getHeaders().get(Trace.TRACE_ID_NAME, String.class);
|
||||
assertNotNull("traceId was null", traceId);
|
||||
assertNull(TraceContextHolder.getCurrentSpan());
|
||||
assertNull(TraceContextHolder.getCurrentTrace());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHeaderCreation() {
|
||||
TraceScope traceScope = this.trace.startSpan("testSendMessage",
|
||||
Trace traceScope = this.trace.startSpan("testSendMessage",
|
||||
new AlwaysSampler(), null);
|
||||
this.channel.send(MessageBuilder.withPayload("hi").build());
|
||||
traceScope.close();
|
||||
this.trace.close(traceScope);
|
||||
assertNotNull("message was null", this.message);
|
||||
|
||||
String spanId = this.message.getHeaders().get(SPAN_ID_NAME, String.class);
|
||||
String spanId = this.message.getHeaders().get(Trace.SPAN_ID_NAME, String.class);
|
||||
assertNotNull("spanId was null", spanId);
|
||||
|
||||
String traceId = this.message.getHeaders().get(TRACE_ID_NAME, String.class);
|
||||
String traceId = this.message.getHeaders().get(Trace.TRACE_ID_NAME, String.class);
|
||||
assertNotNull("traceId was null", traceId);
|
||||
assertNull(TraceContextHolder.getCurrentSpan());
|
||||
assertNull(TraceContextHolder.getCurrentTrace());
|
||||
}
|
||||
|
||||
@Configuration
|
||||
|
||||
@@ -18,8 +18,6 @@ package org.springframework.cloud.sleuth.instrument.integration;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.springframework.cloud.sleuth.Trace.SPAN_ID_NAME;
|
||||
import static org.springframework.cloud.sleuth.Trace.TRACE_ID_NAME;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
@@ -30,10 +28,10 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.IntegrationTest;
|
||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceContextHolder;
|
||||
import org.springframework.cloud.sleuth.TraceScope;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.cloud.sleuth.instrument.integration.TraceContextPropagationChannelInterceptorTests.App;
|
||||
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
|
||||
import org.springframework.cloud.sleuth.trace.TraceContextHolder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
@@ -57,29 +55,29 @@ public class TraceContextPropagationChannelInterceptorTests {
|
||||
private PollableChannel channel;
|
||||
|
||||
@Autowired
|
||||
private Trace trace;
|
||||
private TraceManager trace;
|
||||
|
||||
@After
|
||||
public void close() {
|
||||
TraceContextHolder.removeCurrentSpan();
|
||||
TraceContextHolder.removeCurrentTrace();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpanPropagation() {
|
||||
|
||||
TraceScope traceScope = this.trace.startSpan("testSendMessage", new AlwaysSampler(), null);
|
||||
Trace traceScope = this.trace.startSpan("testSendMessage", new AlwaysSampler(), null);
|
||||
this.channel.send(MessageBuilder.withPayload("hi").build());
|
||||
String expectedSpanId = traceScope.getSpan().getSpanId();
|
||||
traceScope.close();
|
||||
this.trace.close(traceScope);
|
||||
|
||||
Message<?> message = this.channel.receive(0);
|
||||
|
||||
assertNotNull("message was null", message);
|
||||
|
||||
String spanId = message.getHeaders().get(SPAN_ID_NAME, String.class);
|
||||
String spanId = message.getHeaders().get(Trace.SPAN_ID_NAME, String.class);
|
||||
assertEquals("spanId was wrong", expectedSpanId, spanId);
|
||||
|
||||
String traceId = message.getHeaders().get(TRACE_ID_NAME, String.class);
|
||||
String traceId = message.getHeaders().get(Trace.TRACE_ID_NAME, String.class);
|
||||
assertNotNull("traceId was null", traceId);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,18 +17,16 @@
|
||||
package org.springframework.cloud.sleuth.instrument.web;
|
||||
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.springframework.cloud.sleuth.Trace.SPAN_ID_NAME;
|
||||
import static org.springframework.cloud.sleuth.Trace.TRACE_ID_NAME;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.cloud.sleuth.RandomUuidGenerator;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceContextHolder;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.cloud.sleuth.autoconfig.RandomUuidGenerator;
|
||||
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
|
||||
import org.springframework.cloud.sleuth.trace.DefaultTrace;
|
||||
import org.springframework.cloud.sleuth.trace.DefaultTraceManager;
|
||||
import org.springframework.cloud.sleuth.trace.TraceContextHolder;
|
||||
import org.springframework.context.support.StaticApplicationContext;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockFilterChain;
|
||||
@@ -37,6 +35,8 @@ import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
* @author Dave Syer
|
||||
@@ -45,7 +45,7 @@ public class TraceFilterIntegrationTests {
|
||||
|
||||
private StaticApplicationContext context = new StaticApplicationContext();
|
||||
|
||||
private Trace trace = new DefaultTrace(new AlwaysSampler(),
|
||||
private TraceManager traceManager = new DefaultTraceManager(new AlwaysSampler(),
|
||||
new RandomUuidGenerator(), this.context);
|
||||
|
||||
private MockHttpServletRequest request;
|
||||
@@ -55,7 +55,7 @@ public class TraceFilterIntegrationTests {
|
||||
@Before
|
||||
@SneakyThrows
|
||||
public void init() {
|
||||
TraceContextHolder.removeCurrentSpan();
|
||||
TraceContextHolder.removeCurrentTrace();
|
||||
this.context.refresh();
|
||||
this.request = builder().buildRequest(new MockServletContext());
|
||||
this.response = new MockHttpServletResponse();
|
||||
@@ -70,16 +70,16 @@ public class TraceFilterIntegrationTests {
|
||||
|
||||
@Test
|
||||
public void startsNewTrace() throws Exception {
|
||||
TraceFilter filter = new TraceFilter(this.trace);
|
||||
TraceFilter filter = new TraceFilter(this.traceManager);
|
||||
filter.doFilter(this.request, this.response, this.filterChain);
|
||||
assertNull(TraceContextHolder.getCurrentSpan());
|
||||
assertNull(TraceContextHolder.getCurrentTrace());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void continuesSpanFromHeaders() throws Exception {
|
||||
this.request = builder().header(SPAN_ID_NAME, "myspan")
|
||||
.header(TRACE_ID_NAME, "mytrace").buildRequest(new MockServletContext());
|
||||
TraceFilter filter = new TraceFilter(this.trace);
|
||||
this.request = builder().header(Trace.SPAN_ID_NAME, "myspan")
|
||||
.header(Trace.TRACE_ID_NAME, "mytraceManager").buildRequest(new MockServletContext());
|
||||
TraceFilter filter = new TraceFilter(this.traceManager);
|
||||
filter.doFilter(this.request, this.response, this.filterChain);
|
||||
assertNull(TraceContextHolder.getCurrentSpan());
|
||||
}
|
||||
|
||||
@@ -16,24 +16,27 @@
|
||||
|
||||
package org.springframework.cloud.sleuth.instrument.web;
|
||||
|
||||
import static org.mockito.Matchers.anyObject;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.MockitoAnnotations.initMocks;
|
||||
import static org.springframework.cloud.sleuth.Trace.SPAN_ID_NAME;
|
||||
import static org.springframework.cloud.sleuth.Trace.TRACE_ID_NAME;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceScope;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.cloud.sleuth.autoconfig.RandomUuidGenerator;
|
||||
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
|
||||
import org.springframework.cloud.sleuth.trace.DefaultTraceManager;
|
||||
import org.springframework.cloud.sleuth.trace.TraceContextHolder;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockFilterChain;
|
||||
@@ -42,18 +45,18 @@ import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class TraceFilterTests {
|
||||
|
||||
@Mock
|
||||
private Trace trace;
|
||||
private ApplicationEventPublisher publisher;
|
||||
|
||||
@Mock
|
||||
private TraceScope traceScope;
|
||||
private TraceManager trace;
|
||||
|
||||
@Mock
|
||||
private Span span;
|
||||
|
||||
private MockHttpServletRequest request;
|
||||
@@ -64,97 +67,90 @@ public class TraceFilterTests {
|
||||
@SneakyThrows
|
||||
public void init() {
|
||||
initMocks(this);
|
||||
request = builder()
|
||||
.buildRequest(new MockServletContext());
|
||||
response = new MockHttpServletResponse();
|
||||
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||
filterChain = new MockFilterChain();
|
||||
this.trace = new DefaultTraceManager(new AlwaysSampler(),
|
||||
new RandomUuidGenerator(), this.publisher) {
|
||||
@Override
|
||||
protected Trace createTrace(Trace trace, Span span) {
|
||||
TraceFilterTests.this.span= span;
|
||||
return super.createTrace(trace, span);
|
||||
}
|
||||
};
|
||||
this.request = builder().buildRequest(new MockServletContext());
|
||||
this.response = new MockHttpServletResponse();
|
||||
this.response.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||
this.filterChain = new MockFilterChain();
|
||||
}
|
||||
|
||||
public MockHttpServletRequestBuilder builder() {
|
||||
return get("/")
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.header("User-Agent", "MockMvc");
|
||||
return get("/").accept(MediaType.APPLICATION_JSON).header("User-Agent",
|
||||
"MockMvc");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void notTraced() throws Exception {
|
||||
TraceManager trace = Mockito.mock(TraceManager.class);
|
||||
TraceFilter filter = new TraceFilter(trace);
|
||||
|
||||
when(this.trace.startSpan(anyString())).thenReturn(traceScope);
|
||||
|
||||
request = get("/favicon.ico")
|
||||
.accept(MediaType.ALL)
|
||||
this.request = get("/favicon.ico").accept(MediaType.ALL)
|
||||
.buildRequest(new MockServletContext());
|
||||
|
||||
filter.doFilter(request, response, filterChain);
|
||||
filter.doFilter(this.request, this.response, this.filterChain);
|
||||
|
||||
verify(this.trace, never()).startSpan(anyString());
|
||||
|
||||
verify(this.traceScope, never()).close();
|
||||
verify(trace, never()).startSpan(anyString());
|
||||
verify(trace, never()).close(any(Trace.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startsNewTrace() throws Exception {
|
||||
TraceFilter filter = new TraceFilter(trace);
|
||||
|
||||
when(this.trace.startSpan(anyString())).thenReturn(traceScope);
|
||||
|
||||
filter.doFilter(request, response, filterChain);
|
||||
|
||||
verify(this.trace).startSpan(anyString());
|
||||
|
||||
TraceFilter filter = new TraceFilter(this.trace);
|
||||
filter.doFilter(this.request, this.response, this.filterChain);
|
||||
verifyHttpAnnotations();
|
||||
|
||||
verify(this.traceScope).close();
|
||||
assertNull(TraceContextHolder.getCurrentTrace());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void continuesSpanInRequestAttr() throws Exception {
|
||||
request.setAttribute(TraceFilter.TRACE_REQUEST_ATTR, this.traceScope);
|
||||
|
||||
TraceFilter filter = new TraceFilter(trace);
|
||||
filter.doFilter(request, response, filterChain);
|
||||
Trace traceScope = this.trace.startSpan("foo");
|
||||
this.request.setAttribute(TraceFilter.TRACE_REQUEST_ATTR, traceScope);
|
||||
|
||||
verify(this.trace).continueSpan((Span) anyObject());
|
||||
TraceFilter filter = new TraceFilter(this.trace);
|
||||
filter.doFilter(this.request, this.response, this.filterChain);
|
||||
|
||||
verifyHttpAnnotations();
|
||||
|
||||
verify(this.traceScope).close();
|
||||
assertNull(TraceContextHolder.getCurrentTrace());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void continuesSpanFromHeaders() throws Exception {
|
||||
request = builder()
|
||||
.header(SPAN_ID_NAME, "myspan")
|
||||
.header(TRACE_ID_NAME, "mytrace")
|
||||
this.request = builder().header(Trace.SPAN_ID_NAME, "myspan")
|
||||
.header(Trace.TRACE_ID_NAME, "mytrace")
|
||||
.buildRequest(new MockServletContext());
|
||||
|
||||
when(this.trace.startSpan(anyString(), (Span) anyObject())).thenReturn(traceScope);
|
||||
when(this.traceScope.getSpan()).thenReturn(this.span);
|
||||
when(this.span.getSpanId()).thenReturn("myspan");
|
||||
when(this.span.getTraceId()).thenReturn("mytrace");
|
||||
|
||||
TraceFilter filter = new TraceFilter(trace);
|
||||
filter.doFilter(request, response, filterChain);
|
||||
|
||||
verify(this.trace).startSpan(anyString(), (Span) anyObject());
|
||||
TraceFilter filter = new TraceFilter(this.trace);
|
||||
filter.doFilter(this.request, this.response, this.filterChain);
|
||||
|
||||
verifyHttpAnnotations();
|
||||
|
||||
verify(this.traceScope).close();
|
||||
assertNull(TraceContextHolder.getCurrentTrace());
|
||||
}
|
||||
|
||||
|
||||
public void verifyHttpAnnotations() {
|
||||
verify(this.trace).addAnnotation("/http/request/uri", "http://localhost/");
|
||||
verify(this.trace).addAnnotation("/http/request/endpoint", "/");
|
||||
verify(this.trace).addAnnotation("/http/request/method", "GET");
|
||||
verify(this.trace).addAnnotation("/http/request/headers/accept", MediaType.APPLICATION_JSON_VALUE);
|
||||
verify(this.trace).addAnnotation("/http/request/headers/user-agent", "MockMvc");
|
||||
hasAnnotation(this.span, "/http/request/uri", "http://localhost/");
|
||||
hasAnnotation(this.span, "/http/request/endpoint", "/");
|
||||
hasAnnotation(this.span, "/http/request/method", "GET");
|
||||
hasAnnotation(this.span, "/http/request/headers/accept",
|
||||
MediaType.APPLICATION_JSON_VALUE);
|
||||
hasAnnotation(this.span, "/http/request/headers/user-agent", "MockMvc");
|
||||
|
||||
verify(this.trace).addAnnotation("/http/response/status_code", HttpStatus.OK.toString());
|
||||
verify(this.trace).addAnnotation("/http/response/headers/content-type", MediaType.APPLICATION_JSON_VALUE);
|
||||
hasAnnotation(this.span, "/http/response/status_code",
|
||||
HttpStatus.OK.toString());
|
||||
hasAnnotation(this.span, "/http/response/headers/content-type",
|
||||
MediaType.APPLICATION_JSON_VALUE);
|
||||
}
|
||||
|
||||
private void hasAnnotation(Span span, String name, String value) {
|
||||
assertEquals(value, span.getAnnotations().get(name));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package org.springframework.cloud.sleuth.instrument.web.client;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.cloud.sleuth.Trace.PARENT_ID_NAME;
|
||||
import static org.springframework.cloud.sleuth.Trace.SPAN_ID_NAME;
|
||||
import static org.springframework.cloud.sleuth.Trace.TRACE_ID_NAME;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -21,10 +18,12 @@ import org.springframework.cloud.netflix.feign.EnableFeignClients;
|
||||
import org.springframework.cloud.netflix.feign.FeignClient;
|
||||
import org.springframework.cloud.netflix.ribbon.RibbonClient;
|
||||
import org.springframework.cloud.sleuth.MilliSpan;
|
||||
import org.springframework.cloud.sleuth.TraceContextHolder;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.cloud.sleuth.event.ClientReceivedEvent;
|
||||
import org.springframework.cloud.sleuth.event.ClientSentEvent;
|
||||
import org.springframework.cloud.sleuth.instrument.web.TraceWebAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.trace.TraceContextHolder;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -42,8 +41,11 @@ import com.netflix.loadbalancer.ILoadBalancer;
|
||||
import com.netflix.loadbalancer.Server;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringApplicationConfiguration(classes = { TraceWebAutoConfiguration.class, FeignTraceTest.TestConfiguration.class })
|
||||
@WebIntegrationTest(value = "spring.application.name=fooservice", randomPort = true)
|
||||
@SpringApplicationConfiguration(classes = { TraceWebAutoConfiguration.class,
|
||||
FeignTraceTest.TestConfiguration.class })
|
||||
// TODO: make it work with default isolation
|
||||
@WebIntegrationTest(value = { "spring.application.name=fooservice",
|
||||
"hystrix.command.default.execution.isolation.strategy=SEMAPHORE" }, randomPort = true)
|
||||
public class FeignTraceTest {
|
||||
|
||||
@Autowired
|
||||
@@ -52,20 +54,23 @@ public class FeignTraceTest {
|
||||
@Autowired
|
||||
Listener listener;
|
||||
|
||||
@Autowired
|
||||
TraceManager traceManager;
|
||||
|
||||
@After
|
||||
public void close() {
|
||||
TraceContextHolder.removeCurrentSpan();
|
||||
listener.getEvents().clear();
|
||||
TraceContextHolder.removeCurrentTrace();
|
||||
this.listener.getEvents().clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldWorkWhenNotTracing() {
|
||||
// when
|
||||
ResponseEntity<String> response = testFeignInterface.getNoTrace();
|
||||
ResponseEntity<String> response = this.testFeignInterface.getNoTrace();
|
||||
|
||||
// then
|
||||
assertThat(getHeader(response, TRACE_ID_NAME)).isNull();
|
||||
assertThat(listener.getEvents()).isEmpty();
|
||||
assertThat(getHeader(response, Trace.TRACE_ID_NAME)).isNull();
|
||||
assertThat(this.listener.getEvents()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -74,17 +79,17 @@ public class FeignTraceTest {
|
||||
String currentTraceId = "currentTraceId";
|
||||
String currentSpanId = "currentSpanId";
|
||||
String currentParentId = "currentParentId";
|
||||
TraceContextHolder.setCurrentSpan(
|
||||
MilliSpan.builder().traceId(currentTraceId).spanId(currentSpanId).parent(currentParentId).build());
|
||||
this.traceManager.continueSpan(MilliSpan.builder().traceId(currentTraceId)
|
||||
.spanId(currentSpanId).parent(currentParentId).build());
|
||||
|
||||
// when
|
||||
ResponseEntity<String> response = testFeignInterface.getTraceId();
|
||||
ResponseEntity<String> response = this.testFeignInterface.getTraceId();
|
||||
|
||||
// then
|
||||
assertThat(getHeader(response, TRACE_ID_NAME)).isEqualTo(currentTraceId);
|
||||
assertThat(getHeader(response, SPAN_ID_NAME)).isEqualTo(currentSpanId);
|
||||
assertThat(getHeader(response, PARENT_ID_NAME)).isEqualTo(currentParentId);
|
||||
assertThat(listener.getEvents().size()).isEqualTo(2);
|
||||
assertThat(getHeader(response, Trace.TRACE_ID_NAME)).isEqualTo(currentTraceId);
|
||||
assertThat(getHeader(response, Trace.SPAN_ID_NAME)).isEqualTo(currentSpanId);
|
||||
assertThat(getHeader(response, Trace.PARENT_ID_NAME)).isEqualTo(currentParentId);
|
||||
assertThat(this.listener.getEvents().size()).isEqualTo(2);
|
||||
}
|
||||
|
||||
private String getHeader(ResponseEntity<String> response, String name) {
|
||||
@@ -124,16 +129,16 @@ public class FeignTraceTest {
|
||||
|
||||
@EventListener(ClientSentEvent.class)
|
||||
public void sent(ClientSentEvent event) {
|
||||
events.add(event);
|
||||
this.events.add(event);
|
||||
}
|
||||
|
||||
@EventListener(ClientReceivedEvent.class)
|
||||
public void received(ClientReceivedEvent event) {
|
||||
events.add(event);
|
||||
this.events.add(event);
|
||||
}
|
||||
|
||||
public List<ApplicationEvent> getEvents() {
|
||||
return events;
|
||||
return this.events;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,14 +146,16 @@ public class FeignTraceTest {
|
||||
public static class FooController {
|
||||
|
||||
@RequestMapping(value = "/notrace", method = RequestMethod.GET)
|
||||
public String notrace(@RequestHeader(name = TRACE_ID_NAME, required = false) String traceId) {
|
||||
public String notrace(
|
||||
@RequestHeader(name = Trace.TRACE_ID_NAME, required = false) String traceId) {
|
||||
assertThat(traceId).isNull();
|
||||
return "OK";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/traceid", method = RequestMethod.GET)
|
||||
public String traceId(@RequestHeader(TRACE_ID_NAME) String traceId, @RequestHeader(SPAN_ID_NAME) String spanId,
|
||||
@RequestHeader(PARENT_ID_NAME) String parentId) {
|
||||
public String traceId(@RequestHeader(Trace.TRACE_ID_NAME) String traceId,
|
||||
@RequestHeader(Trace.SPAN_ID_NAME) String spanId,
|
||||
@RequestHeader(Trace.PARENT_ID_NAME) String parentId) {
|
||||
assertThat(traceId).isNotEmpty();
|
||||
assertThat(parentId).isNotEmpty();
|
||||
assertThat(spanId).isNotEmpty();
|
||||
@@ -165,7 +172,7 @@ public class FeignTraceTest {
|
||||
@Bean
|
||||
public ILoadBalancer ribbonLoadBalancer() {
|
||||
BaseLoadBalancer balancer = new BaseLoadBalancer();
|
||||
balancer.setServersList(Arrays.asList(new Server("localhost", port)));
|
||||
balancer.setServersList(Arrays.asList(new Server("localhost", this.port)));
|
||||
return balancer;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,11 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.cloud.sleuth.MilliSpan;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceContextHolder;
|
||||
import org.springframework.cloud.sleuth.autoconfig.RandomUuidGenerator;
|
||||
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
|
||||
import org.springframework.cloud.sleuth.trace.DefaultTraceManager;
|
||||
import org.springframework.cloud.sleuth.trace.TraceContextHolder;
|
||||
import org.springframework.context.support.StaticApplicationContext;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.test.web.client.MockMvcClientHttpRequestFactory;
|
||||
@@ -48,28 +52,33 @@ public class TraceRestTemplateInterceptorTests {
|
||||
private MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new TestController())
|
||||
.build();
|
||||
|
||||
private RestTemplate template = new RestTemplate(new MockMvcClientHttpRequestFactory(
|
||||
this.mockMvc));
|
||||
private RestTemplate template = new RestTemplate(
|
||||
new MockMvcClientHttpRequestFactory(this.mockMvc));
|
||||
|
||||
private DefaultTraceManager traces;
|
||||
|
||||
private StaticApplicationContext publisher = new StaticApplicationContext();
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.template
|
||||
.setInterceptors(Arrays
|
||||
.<ClientHttpRequestInterceptor> asList(new TraceRestTemplateInterceptor()));
|
||||
this.publisher.refresh();
|
||||
this.traces = new DefaultTraceManager(new AlwaysSampler(),
|
||||
new RandomUuidGenerator(), this.publisher);
|
||||
this.template.setInterceptors(Arrays.<ClientHttpRequestInterceptor>asList(
|
||||
new TraceRestTemplateInterceptor(this.traces)));
|
||||
}
|
||||
|
||||
@After
|
||||
public void clean() {
|
||||
TraceContextHolder.removeCurrentSpan();
|
||||
TraceContextHolder.removeCurrentTrace();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headersAddedWhenTracing() {
|
||||
TraceContextHolder.setCurrentSpan(MilliSpan.builder().traceId("foo")
|
||||
.spanId("bar").build());
|
||||
this.traces.continueSpan(MilliSpan.builder().traceId("foo").spanId("bar").build());
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, String> headers = this.template.getForEntity("/", Map.class)
|
||||
.getBody();
|
||||
.getBody();
|
||||
assertEquals("bar", headers.get(Trace.SPAN_ID_NAME));
|
||||
assertEquals("foo", headers.get(Trace.TRACE_ID_NAME));
|
||||
}
|
||||
@@ -78,7 +87,7 @@ public class TraceRestTemplateInterceptorTests {
|
||||
public void headersNotAddedWhenNotTracing() {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, String> headers = this.template.getForEntity("/", Map.class)
|
||||
.getBody();
|
||||
.getBody();
|
||||
assertFalse("Wrong headers: " + headers, headers.containsKey(Trace.SPAN_ID_NAME));
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import java.util.Random;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -32,7 +32,7 @@ import org.springframework.stereotype.Component;
|
||||
public class SampleBackground {
|
||||
|
||||
@Autowired
|
||||
private Trace trace;
|
||||
private TraceManager traceManager;
|
||||
|
||||
@SneakyThrows
|
||||
@Async
|
||||
@@ -40,7 +40,7 @@ public class SampleBackground {
|
||||
final Random random = new Random();
|
||||
int millis = random.nextInt(1000);
|
||||
Thread.sleep(millis);
|
||||
this.trace.addAnnotation("background-sleep-millis", String.valueOf(millis));
|
||||
this.traceManager.addAnnotation("background-sleep-millis", String.valueOf(millis));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
server:
|
||||
port: 3382
|
||||
|
||||
sample:
|
||||
zipkin:
|
||||
enabled: false
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: testSleuthRibbon
|
||||
|
||||
@@ -21,7 +21,7 @@ import java.util.Random;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -32,7 +32,7 @@ import org.springframework.stereotype.Component;
|
||||
public class SampleBackground {
|
||||
|
||||
@Autowired
|
||||
private Trace trace;
|
||||
private TraceManager traceManager;
|
||||
|
||||
@SneakyThrows
|
||||
@Async
|
||||
@@ -40,7 +40,7 @@ public class SampleBackground {
|
||||
final Random random = new Random();
|
||||
int millis = random.nextInt(1000);
|
||||
Thread.sleep(millis);
|
||||
this.trace.addAnnotation("background-sleep-millis", String.valueOf(millis));
|
||||
this.traceManager.addAnnotation("background-sleep-millis", String.valueOf(millis));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,21 +19,21 @@ package sample;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
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.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceContextHolder;
|
||||
import org.springframework.cloud.sleuth.TraceScope;
|
||||
import org.springframework.cloud.sleuth.TraceAccessor;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@@ -44,7 +44,9 @@ ApplicationListener<EmbeddedServletContainerInitializedEvent> {
|
||||
@Autowired
|
||||
private RestTemplate restTemplate;
|
||||
@Autowired
|
||||
private Trace trace;
|
||||
private TraceManager traceManager;
|
||||
@Autowired
|
||||
private TraceAccessor accessor;
|
||||
@Autowired
|
||||
private SampleBackground controller;
|
||||
private int port;
|
||||
@@ -68,8 +70,8 @@ ApplicationListener<EmbeddedServletContainerInitializedEvent> {
|
||||
final Random random = new Random();
|
||||
int millis = random.nextInt(1000);
|
||||
Thread.sleep(millis);
|
||||
SampleController.this.trace.addAnnotation("callable-sleep-millis", String.valueOf(millis));
|
||||
Span currentSpan = TraceContextHolder.getCurrentSpan();
|
||||
SampleController.this.traceManager.addAnnotation("callable-sleep-millis", String.valueOf(millis));
|
||||
Span currentSpan = SampleController.this.accessor.getCurrentSpan();
|
||||
return "async hi: " + currentSpan;
|
||||
}
|
||||
};
|
||||
@@ -87,24 +89,24 @@ ApplicationListener<EmbeddedServletContainerInitializedEvent> {
|
||||
final Random random = new Random();
|
||||
int millis = random.nextInt(1000);
|
||||
Thread.sleep(millis);
|
||||
this.trace.addAnnotation("random-sleep-millis", String.valueOf(millis));
|
||||
this.traceManager.addAnnotation("random-sleep-millis", String.valueOf(millis));
|
||||
return "hi2";
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@RequestMapping("/traced")
|
||||
public String traced() {
|
||||
TraceScope scope = this.trace.startSpan("customTraceEndpoint",
|
||||
Trace scope = this.traceManager.startSpan("customTraceEndpoint",
|
||||
new AlwaysSampler(), null);
|
||||
final Random random = new Random();
|
||||
int millis = random.nextInt(1000);
|
||||
log.info("Sleeping for {} millis", millis);
|
||||
Thread.sleep(millis);
|
||||
this.trace.addAnnotation("random-sleep-millis", String.valueOf(millis));
|
||||
this.traceManager.addAnnotation("random-sleep-millis", String.valueOf(millis));
|
||||
|
||||
String s = this.restTemplate.getForObject("http://localhost:" + this.port
|
||||
+ "/call", String.class);
|
||||
scope.close();
|
||||
this.traceManager.close(scope);
|
||||
return "traced/" + s;
|
||||
}
|
||||
|
||||
@@ -115,7 +117,7 @@ ApplicationListener<EmbeddedServletContainerInitializedEvent> {
|
||||
int millis = random.nextInt(1000);
|
||||
log.info("Sleeping for {} millis", millis);
|
||||
Thread.sleep(millis);
|
||||
this.trace.addAnnotation("random-sleep-millis", String.valueOf(millis));
|
||||
this.traceManager.addAnnotation("random-sleep-millis", String.valueOf(millis));
|
||||
|
||||
String s = this.restTemplate.getForObject("http://localhost:" + this.port
|
||||
+ "/call", String.class);
|
||||
|
||||
@@ -11,4 +11,4 @@ logging:
|
||||
|
||||
sample:
|
||||
zipkin:
|
||||
# enabled: false
|
||||
enabled: false
|
||||
@@ -21,7 +21,7 @@ import java.util.Random;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -32,7 +32,7 @@ import org.springframework.stereotype.Component;
|
||||
public class SampleBackground {
|
||||
|
||||
@Autowired
|
||||
private Trace trace;
|
||||
private TraceManager traceManager;
|
||||
|
||||
@SneakyThrows
|
||||
@Async
|
||||
@@ -40,7 +40,7 @@ public class SampleBackground {
|
||||
final Random random = new Random();
|
||||
int millis = random.nextInt(1000);
|
||||
Thread.sleep(millis);
|
||||
this.trace.addAnnotation("background-sleep-millis", String.valueOf(millis));
|
||||
this.traceManager.addAnnotation("background-sleep-millis", String.valueOf(millis));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,21 +19,21 @@ package sample;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
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.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceContextHolder;
|
||||
import org.springframework.cloud.sleuth.TraceScope;
|
||||
import org.springframework.cloud.sleuth.TraceAccessor;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@@ -44,7 +44,9 @@ ApplicationListener<EmbeddedServletContainerInitializedEvent> {
|
||||
@Autowired
|
||||
private RestTemplate restTemplate;
|
||||
@Autowired
|
||||
private Trace trace;
|
||||
private TraceManager trace;
|
||||
@Autowired
|
||||
private TraceAccessor accessor;
|
||||
@Autowired
|
||||
private SampleBackground controller;
|
||||
private int port;
|
||||
@@ -69,7 +71,7 @@ ApplicationListener<EmbeddedServletContainerInitializedEvent> {
|
||||
int millis = random.nextInt(1000);
|
||||
Thread.sleep(millis);
|
||||
SampleController.this.trace.addAnnotation("callable-sleep-millis", String.valueOf(millis));
|
||||
Span currentSpan = TraceContextHolder.getCurrentSpan();
|
||||
Span currentSpan = SampleController.this.accessor.getCurrentSpan();
|
||||
return "async hi: " + currentSpan;
|
||||
}
|
||||
};
|
||||
@@ -94,7 +96,7 @@ ApplicationListener<EmbeddedServletContainerInitializedEvent> {
|
||||
@SneakyThrows
|
||||
@RequestMapping("/traced")
|
||||
public String traced() {
|
||||
TraceScope scope = this.trace.startSpan("customTraceEndpoint",
|
||||
Trace scope = this.trace.startSpan("customTraceEndpoint",
|
||||
new AlwaysSampler(), null);
|
||||
final Random random = new Random();
|
||||
int millis = random.nextInt(1000);
|
||||
@@ -104,7 +106,7 @@ ApplicationListener<EmbeddedServletContainerInitializedEvent> {
|
||||
|
||||
String s = this.restTemplate.getForObject("http://localhost:" + this.port
|
||||
+ "/call", String.class);
|
||||
scope.close();
|
||||
this.trace.close(scope);
|
||||
return "traced/" + s;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,15 +32,13 @@ import org.springframework.cloud.sleuth.MilliSpan;
|
||||
import org.springframework.cloud.sleuth.Sampler;
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceScope;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.event.ClientReceivedEvent;
|
||||
import org.springframework.cloud.sleuth.event.ClientSentEvent;
|
||||
import org.springframework.cloud.sleuth.event.ServerReceivedEvent;
|
||||
import org.springframework.cloud.sleuth.event.ServerSentEvent;
|
||||
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
|
||||
import org.springframework.cloud.sleuth.stream.SleuthStreamAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.stream.StreamSpanListener;
|
||||
import org.springframework.cloud.sleuth.stream.StreamSpanListenerTests.TestConfiguration;
|
||||
import org.springframework.cloud.stream.binder.local.config.LocalBinderAutoConfiguration;
|
||||
import org.springframework.cloud.stream.config.ChannelBindingAutoConfiguration;
|
||||
@@ -59,7 +57,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
public class StreamSpanListenerTests {
|
||||
|
||||
@Autowired
|
||||
private Trace trace;
|
||||
private TraceManager traceManager;
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext application;
|
||||
@@ -74,8 +72,8 @@ public class StreamSpanListenerTests {
|
||||
|
||||
@Test
|
||||
public void acquireAndRelease() {
|
||||
TraceScope context = this.trace.startSpan("foo");
|
||||
context.close();
|
||||
Trace context = this.traceManager.startSpan("foo");
|
||||
this.traceManager.close(context);
|
||||
assertEquals(1, this.test.spans.size());
|
||||
}
|
||||
|
||||
@@ -83,14 +81,14 @@ public class StreamSpanListenerTests {
|
||||
public void rpcAnnotations() {
|
||||
Span parent = MilliSpan.builder().traceId("xxxx").name("parent").remote(true)
|
||||
.build();
|
||||
TraceScope context = this.trace.startSpan("child", parent);
|
||||
Trace context = this.traceManager.startSpan("child", parent);
|
||||
this.application.publishEvent(new ClientSentEvent(this, context.getSpan()));
|
||||
this.application
|
||||
.publishEvent(new ServerReceivedEvent(this, parent, context.getSpan()));
|
||||
this.application
|
||||
.publishEvent(new ServerSentEvent(this, parent, context.getSpan()));
|
||||
this.application.publishEvent(new ClientReceivedEvent(this, context.getSpan()));
|
||||
context.close();
|
||||
this.traceManager.close(context);
|
||||
assertEquals(2, this.test.spans.size());
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ import org.springframework.cloud.sleuth.MilliSpan;
|
||||
import org.springframework.cloud.sleuth.Sampler;
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceScope;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.event.ClientReceivedEvent;
|
||||
import org.springframework.cloud.sleuth.event.ClientSentEvent;
|
||||
@@ -58,7 +58,7 @@ import com.github.kristofa.brave.SpanCollector;
|
||||
public class ZipkinSpanListenerTests {
|
||||
|
||||
@Autowired
|
||||
private Trace trace;
|
||||
private TraceManager traceManager;
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext application;
|
||||
@@ -73,20 +73,20 @@ public class ZipkinSpanListenerTests {
|
||||
|
||||
@Test
|
||||
public void acquireAndRelease() {
|
||||
TraceScope context = this.trace.startSpan("foo");
|
||||
context.close();
|
||||
Trace context = this.traceManager.startSpan("foo");
|
||||
this.traceManager.close(context);
|
||||
assertEquals(1, this.test.spans.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rpcAnnotations() {
|
||||
Span parent = MilliSpan.builder().traceId("xxxx").name("parent").remote(true).build();
|
||||
TraceScope context = this.trace.startSpan("child", parent);
|
||||
Trace context = this.traceManager.startSpan("child", parent);
|
||||
this.application.publishEvent(new ClientSentEvent(this, context.getSpan()));
|
||||
this.application.publishEvent(new ServerReceivedEvent(this, parent, context.getSpan()));
|
||||
this.application.publishEvent(new ServerSentEvent(this, parent, context.getSpan()));
|
||||
this.application.publishEvent(new ClientReceivedEvent(this, context.getSpan()));
|
||||
context.close();
|
||||
this.traceManager.close(context);
|
||||
assertEquals(2, this.test.spans.size());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user