From ffa97c1f2016a0eebc5b3dacf0b2e5288c893728 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Wed, 9 Sep 2015 15:00:12 +0100 Subject: [PATCH] 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). --- .../cloud/sleuth/MilliSpan.java | 2 +- .../springframework/cloud/sleuth/Trace.java | 117 ++++++----------- .../cloud/sleuth/TraceAccessor.java | 31 +++++ .../cloud/sleuth/TraceManager.java | 111 ++++++++++++++++ .../cloud/sleuth/TraceScope.java | 112 ---------------- .../{ => autoconfig}/RandomUuidGenerator.java | 4 +- .../autoconfig/TraceAutoConfiguration.java | 12 +- .../sleuth/instrument/TraceCallable.java | 40 ++---- .../sleuth/instrument/TraceDelegate.java | 33 +++-- .../sleuth/instrument/TraceRunnable.java | 39 ++---- .../async/AsyncDefaultAutoConfiguration.java | 4 +- .../instrument/async/LazyTraceExecutor.java | 14 +- .../executor/TraceableExecutorService.java | 22 ++-- .../TraceableScheduledExecutorService.java | 24 ++-- .../TraceCommand.java | 35 ++--- .../integration/SpanMessageHeaders.java | 25 ++-- .../integration/TraceChannelInterceptor.java | 59 ++++----- ...eContextPropagationChannelInterceptor.java | 66 ++++------ ...aceSpringIntegrationAutoConfiguration.java | 11 +- .../scheduling/TraceSchedulingAspect.java | 12 +- .../TraceSchedulingAutoConfiguration.java | 6 +- .../sleuth/instrument/web/TraceFilter.java | 77 +++++------ .../web/TraceHandlerInterceptor.java | 39 +++--- .../sleuth/instrument/web/TraceWebAspect.java | 25 ++-- .../web/TraceWebAutoConfiguration.java | 14 +- .../TraceFeignClientAutoConfiguration.java | 36 +++-- .../client/TraceRestTemplateInterceptor.java | 34 ++--- .../TraceWebClientAutoConfiguration.java | 8 +- .../instrument/zuul/TracePostZuulFilter.java | 13 +- .../instrument/zuul/TracePreZuulFilter.java | 33 +++-- .../TraceRestClientRibbonCommandFactory.java | 67 ++++++---- .../zuul/TraceZuulAutoConfiguration.java | 17 +-- .../log/SleuthLogAutoConfiguration.java | 4 +- .../cloud/sleuth/log/Slf4jSpanListener.java | 12 +- .../sleuth/sampler/IsTracingSampler.java | 4 +- .../cloud/sleuth/template/TraceCallback.java | 23 ++++ .../sleuth/template/TraceOperations.java | 27 ++++ .../sleuth/{ => template}/TraceTemplate.java | 28 ++-- ...ultTrace.java => DefaultTraceManager.java} | 120 +++++++++++++---- .../{NullScope.java => trace/NullTrace.java} | 30 ++--- .../{ => trace}/TraceContextHolder.java | 21 ++- ...sts.java => DefaultTraceManagerTests.java} | 27 ++-- .../TraceableExecutorServiceTests.java | 99 ++++++-------- .../TraceChannelInterceptorTests.java | 31 ++--- ...extPropagationChannelInterceptorTests.java | 18 ++- .../web/TraceFilterIntegrationTests.java | 26 ++-- .../instrument/web/TraceFilterTests.java | 124 +++++++++--------- .../instrument/web/client/FeignTraceTest.java | 57 ++++---- .../TraceRestTemplateInterceptorTests.java | 31 +++-- .../main/java/sample/SampleBackground.java | 6 +- .../src/main/resources/application.yml | 4 + .../main/java/sample/SampleBackground.java | 6 +- .../main/java/sample/SampleController.java | 28 ++-- .../src/main/resources/application.yml | 2 +- .../main/java/sample/SampleBackground.java | 6 +- .../main/java/sample/SampleController.java | 20 +-- .../stream/StreamSpanListenerTests.java | 14 +- .../zipkin/ZipkinSpanListenerTests.java | 12 +- 58 files changed, 1005 insertions(+), 917 deletions(-) create mode 100644 spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/TraceAccessor.java create mode 100644 spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/TraceManager.java delete mode 100644 spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/TraceScope.java rename spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/{ => autoconfig}/RandomUuidGenerator.java (88%) rename spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/{concurrent => }/executor/TraceableExecutorService.java (83%) rename spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/{concurrent => }/executor/TraceableScheduledExecutorService.java (80%) rename spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/{circuitbreaker => hystrix}/TraceCommand.java (59%) create mode 100644 spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/template/TraceCallback.java create mode 100644 spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/template/TraceOperations.java rename spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/{ => template}/TraceTemplate.java (65%) rename spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/trace/{DefaultTrace.java => DefaultTraceManager.java} (56%) rename spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/{NullScope.java => trace/NullTrace.java} (64%) rename spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/{ => trace}/TraceContextHolder.java (73%) rename spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/{DefaultTraceTests.java => DefaultTraceManagerTests.java} (83%) rename spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/{concurrent => }/executor/TraceableExecutorServiceTests.java (59%) diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/MilliSpan.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/MilliSpan.java index 6655db673..92c5c4865 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/MilliSpan.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/MilliSpan.java @@ -46,7 +46,7 @@ public class MilliSpan implements Span { private final List timelineAnnotations = new ArrayList<>(); public MilliSpan(long begin, long end, String name, String traceId, List 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; diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Trace.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Trace.java index 32039169d..58840e7ac 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Trace.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Trace.java @@ -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: - *
    - *
  • Create a new Span which has this thread's currentSpan as one of its parents.
  • - *
  • Set currentSpan to the new Span.
  • - *
  • Create a TraceSpan object to manage the new Span.
  • - *
- * - * Closing a TraceScope does a few things: - *
    - *
  • It closes the span which the scope was managing.
  • - *
  • Set currentSpan to the previous currentSpan (which may be null).
  • - *
+ * @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 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 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. - *

- * 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. - *

- * 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 - */ - TraceScope startSpan(String name, Sampler 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); + } - Callable wrap(Callable 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); } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/TraceAccessor.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/TraceAccessor.java new file mode 100644 index 000000000..566621f2c --- /dev/null +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/TraceAccessor.java @@ -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(); + +} diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/TraceManager.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/TraceManager.java new file mode 100644 index 000000000..c474a925c --- /dev/null +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/TraceManager.java @@ -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: + *

    + *
  • Create a new Span which has this thread's currentSpan as one of its parents.
  • + *
  • Set currentSpan to the new Span.
  • + *
  • Create a TraceSpan object to manage the new Span.
  • + *
+ * + * Closing a TraceScope does a few things: + *
    + *
  • It closes the span which the scope was managing.
  • + *
  • Set currentSpan to the previous currentSpan (which may be null).
  • + *
+ */ +public interface TraceManager extends TraceAccessor { + + /** + * Creates a trace wrapping a new span. + *

+ * 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. + *

+ * 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 + */ + Trace startSpan(String name, Sampler 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); + + Callable wrap(Callable callable); + + Runnable wrap(Runnable runnable); +} diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/TraceScope.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/TraceScope.java deleted file mode 100644 index af9f0569e..000000000 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/TraceScope.java +++ /dev/null @@ -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); - } - } - -} diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/RandomUuidGenerator.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/RandomUuidGenerator.java similarity index 88% rename from spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/RandomUuidGenerator.java rename to spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/RandomUuidGenerator.java index b4569e370..4f3260556 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/RandomUuidGenerator.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/RandomUuidGenerator.java @@ -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 */ diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/TraceAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/TraceAutoConfiguration.java index 513422f52..b18eca521 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/TraceAutoConfiguration.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/TraceAutoConfiguration.java @@ -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 defaultSampler() { + public Sampler defaultTraceSampler() { return new IsTracingSampler(); } @Bean @ConditionalOnMissingBean - public Trace trace(Sampler sampler, IdGenerator idGenerator, + public DefaultTraceManager traceManager(Sampler sampler, IdGenerator idGenerator, ApplicationEventPublisher publisher) { - return new DefaultTrace(sampler, idGenerator, publisher); + return new DefaultTraceManager(sampler, idGenerator, publisher); } } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceCallable.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceCallable.java index c67f937a9..88f03a176 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceCallable.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceCallable.java @@ -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 extends TraceDelegate> implements Callable { +@EqualsAndHashCode(callSuper = false) +public class TraceCallable extends TraceDelegate>implements Callable { - public TraceCallable(Trace trace, Callable delegate) { - super(trace, delegate); + public TraceCallable(TraceManager traceManager, Callable delegate) { + super(traceManager, delegate); } - public TraceCallable(Trace trace, Callable delegate, Span parent) { - super(trace, delegate, parent); - } - - public TraceCallable(Trace trace, Callable delegate, Span parent, String name) { - super(trace, delegate, parent, name); + public TraceCallable(TraceManager traceManager, Callable 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); + } } } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceDelegate.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceDelegate.java index 5dec87937..14242e574 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceDelegate.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceDelegate.java @@ -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 { - 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() { diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceRunnable.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceRunnable.java index c2079212b..ab367f47b 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceRunnable.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/TraceRunnable.java @@ -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 implements Runnable { +@EqualsAndHashCode(callSuper = false) +public class TraceRunnable extends TraceDelegateimplements 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); + } } } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/AsyncDefaultAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/AsyncDefaultAutoConfiguration.java index 52cd44943..3591b73e1 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/AsyncDefaultAutoConfiguration.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/AsyncDefaultAutoConfiguration.java @@ -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 { diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LazyTraceExecutor.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LazyTraceExecutor.java index 5638c4064..8a4fd5f37 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LazyTraceExecutor.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LazyTraceExecutor.java @@ -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)); } } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/concurrent/executor/TraceableExecutorService.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/executor/TraceableExecutorService.java similarity index 83% rename from spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/concurrent/executor/TraceableExecutorService.java rename to spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/executor/TraceableExecutorService.java index 6430cbe97..530f1bf7e 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/concurrent/executor/TraceableExecutorService.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/executor/TraceableExecutorService.java @@ -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 Future submit(Callable task) { - Callable c = new TraceCallable<>(this.trace, task); + Callable c = new TraceCallable<>(this.traceManager, task); return this.delegate.submit(c); } @Override public Future 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); } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/concurrent/executor/TraceableScheduledExecutorService.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/executor/TraceableScheduledExecutorService.java similarity index 80% rename from spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/concurrent/executor/TraceableScheduledExecutorService.java rename to spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/executor/TraceableScheduledExecutorService.java index 5b577a83d..5a81da162 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/concurrent/executor/TraceableScheduledExecutorService.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/executor/TraceableScheduledExecutorService.java @@ -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 ScheduledFuture schedule(Callable callable, long delay, TimeUnit unit) { - Callable c = new TraceCallable<>(this.trace,callable); + Callable 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); } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/circuitbreaker/TraceCommand.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/hystrix/TraceCommand.java similarity index 59% rename from spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/circuitbreaker/TraceCommand.java rename to spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/hystrix/TraceCommand.java index 1b6b88eb9..965c13993 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/circuitbreaker/TraceCommand.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/hystrix/TraceCommand.java @@ -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 extends HystrixCommand { - 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); } } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/integration/SpanMessageHeaders.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/integration/SpanMessageHeaders.java index 93e060156..0e68ca724 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/integration/SpanMessageHeaders.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/integration/SpanMessageHeaders.java @@ -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 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 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) { diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/integration/TraceChannelInterceptor.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/integration/TraceChannelInterceptor.java index 260c78e6d..0cce639c9 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/integration/TraceChannelInterceptor.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/integration/TraceChannelInterceptor.java @@ -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 traceScopeHolder = new ThreadLocal(); + private ThreadLocal traceManagerScopeHolder = new ThreadLocal(); - private ThreadLocal spanHolder = new ThreadLocal(); + 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) { diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/integration/TraceContextPropagationChannelInterceptor.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/integration/TraceContextPropagationChannelInterceptor.java index 26f538c07..f139d07ec 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/integration/TraceContextPropagationChannelInterceptor.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/integration/TraceContextPropagationChannelInterceptor.java @@ -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 ORIGINAL_CONTEXT = new ThreadLocal<>(); + private final TraceManager traceManager; + + private final static ThreadLocal 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 { @@ -143,16 +127,16 @@ implements ExecutorChannelInterceptor { Map 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 + '}'; } } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/integration/TraceSpringIntegrationAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/integration/TraceSpringIntegrationAutoConfiguration.java index f7dcbcc63..805cbc569 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/integration/TraceSpringIntegrationAutoConfiguration.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/integration/TraceSpringIntegrationAutoConfiguration.java @@ -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); } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/scheduling/TraceSchedulingAspect.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/scheduling/TraceSchedulingAspect.java index 9796a6cbc..f7e6487f7 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/scheduling/TraceSchedulingAspect.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/scheduling/TraceSchedulingAspect.java @@ -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); } } } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/scheduling/TraceSchedulingAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/scheduling/TraceSchedulingAutoConfiguration.java index 093bb5851..caf6b964a 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/scheduling/TraceSchedulingAutoConfiguration.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/scheduling/TraceSchedulingAutoConfiguration.java @@ -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); } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceFilter.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceFilter.java index 691ecc68d..4b9cca34e 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceFilter.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceFilter.java @@ -15,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 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); } } } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceHandlerInterceptor.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceHandlerInterceptor.java index ace339b2f..15ef73878 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceHandlerInterceptor.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceHandlerInterceptor.java @@ -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); } } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceWebAspect.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceWebAspect.java index c62f5e8b4..377cc66e7 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceWebAspect.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceWebAspect.java @@ -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 *

@@ -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 callable = (Callable) 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; diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceWebAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceWebAutoConfiguration.java index 5ac4f41bf..13cbd3b39 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceWebAutoConfiguration.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceWebAutoConfiguration.java @@ -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); } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceFeignClientAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceFeignClientAutoConfiguration.java index 9347b3daa..dd16b3fbb 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceFeignClientAutoConfiguration.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceFeignClientAutoConfiguration.java @@ -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> 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(); + } + } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceRestTemplateInterceptor.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceRestTemplateInterceptor.java index 26f768f2a..986e145f5 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceRestTemplateInterceptor.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceRestTemplateInterceptor.java @@ -15,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(); + } + } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceWebClientAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceWebClientAutoConfiguration.java index 6776de6ae..12f2e2748 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceWebClientAutoConfiguration.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceWebClientAutoConfiguration.java @@ -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 diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TracePostZuulFilter.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TracePostZuulFilter.java index 4d22b21c4..788ecbbe2 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TracePostZuulFilter.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TracePostZuulFilter.java @@ -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(); + } } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TracePreZuulFilter.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TracePreZuulFilter.java index 18d7ad309..ff9a0c486 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TracePreZuulFilter.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TracePreZuulFilter.java @@ -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 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; diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TraceRestClientRibbonCommandFactory.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TraceRestClientRibbonCommandFactory.java index ce4477197..11d93a60e 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TraceRestClientRibbonCommandFactory.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TraceRestClientRibbonCommandFactory.java @@ -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 headers, MultiValueMap 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 headers, + MultiValueMap 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(); + } + } } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TraceZuulAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TraceZuulAutoConfiguration.java index 2b47e4f07..f1d119b0c 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TraceZuulAutoConfiguration.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TraceZuulAutoConfiguration.java @@ -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); } } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/log/SleuthLogAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/log/SleuthLogAutoConfiguration.java index d8d3c2619..23f3c8eba 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/log/SleuthLogAutoConfiguration.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/log/SleuthLogAutoConfiguration.java @@ -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 { diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/log/Slf4jSpanListener.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/log/Slf4jSpanListener.java index f4adf3904..e2108a087 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/log/Slf4jSpanListener.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/log/Slf4jSpanListener.java @@ -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); } } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/sampler/IsTracingSampler.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/sampler/IsTracingSampler.java index ebe3e0a4a..01cb0faa6 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/sampler/IsTracingSampler.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/sampler/IsTracingSampler.java @@ -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 { @Override public boolean next(Void info) { - return TraceContextHolder.getCurrentSpan() != null; + return TraceContextHolder.isTracing(); } } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/template/TraceCallback.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/template/TraceCallback.java new file mode 100644 index 000000000..dbddd14e4 --- /dev/null +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/template/TraceCallback.java @@ -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 doInTrace(Trace traceScope); +} \ No newline at end of file diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/template/TraceOperations.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/template/TraceOperations.java new file mode 100644 index 000000000..d67e2cfac --- /dev/null +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/template/TraceOperations.java @@ -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 trace(TraceCallback task); + +} diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/TraceTemplate.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/template/TraceTemplate.java similarity index 65% rename from spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/TraceTemplate.java rename to spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/template/TraceTemplate.java index e3d30579b..1fd6bacd6 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/TraceTemplate.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/template/TraceTemplate.java @@ -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 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 trace(final TraceCallback callback) { - DelegateCallback delegate = new DelegateCallback<>(this.trace); - if (delegate.getParent() != null) { - TraceScope traceScope = delegate.startSpan(); + if (TraceContextHolder.isTracing()) { + DelegateCallback 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 extends TraceDelegate> { - public DelegateCallback(Trace trace) { + public DelegateCallback(TraceManager trace) { super(trace, null); } @Override - protected TraceScope startSpan() { + protected Trace startSpan() { return super.startSpan(); } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/trace/DefaultTrace.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/trace/DefaultTraceManager.java similarity index 56% rename from spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/trace/DefaultTrace.java rename to spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/trace/DefaultTraceManager.java index b2fd06327..fd3de6776 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/trace/DefaultTrace.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/trace/DefaultTraceManager.java @@ -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 defaultSampler; @@ -45,7 +45,7 @@ public class DefaultTrace implements Trace { private final ApplicationEventPublisher publisher; - public DefaultTrace(Sampler defaultSampler, IdGenerator idGenerator, + public DefaultTraceManager(Sampler 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 TraceScope startSpan(String name, Sampler s, T info) { + public Trace startSpan(String name, Sampler 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 Callable wrap(Callable 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; } + } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/NullScope.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/trace/NullTrace.java similarity index 64% rename from spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/NullScope.java rename to spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/trace/NullTrace.java index 21a8009e4..ad0b49373 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/NullScope.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/trace/NullTrace.java @@ -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"; } } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/TraceContextHolder.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/trace/TraceContextHolder.java similarity index 73% rename from spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/TraceContextHolder.java rename to spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/trace/TraceContextHolder.java index 6d8021eef..7aebc7222 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/TraceContextHolder.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/trace/TraceContextHolder.java @@ -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 currentSpan = new NamedThreadLocal<>("Trace Context"); - public static Span getCurrentSpan() { + private static final ThreadLocal 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(); } diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/DefaultTraceTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/DefaultTraceManagerTests.java similarity index 83% rename from spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/DefaultTraceTests.java rename to spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/DefaultTraceManagerTests.java index 1748c7af2..605a282e8 100644 --- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/DefaultTraceTests.java +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/DefaultTraceManagerTests.java @@ -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); } } } diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/concurrent/executor/TraceableExecutorServiceTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/executor/TraceableExecutorServiceTests.java similarity index 59% rename from spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/concurrent/executor/TraceableExecutorServiceTests.java rename to spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/executor/TraceableExecutorServiceTests.java index 58f8b0f87..7d06bbf3e 100644 --- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/concurrent/executor/TraceableExecutorServiceTests.java +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/executor/TraceableExecutorServiceTests.java @@ -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 captor = ArgumentCaptor .forClass(ApplicationEvent.class); - verify(publisher, atLeast(NUM_SPANS)).publishEvent(captor.capture()); + verify(this.publisher, atLeast(this.NUM_SPANS)).publishEvent(captor.capture()); List 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 captor = ArgumentCaptor .forClass(ApplicationEvent.class); - verify(publisher, atLeast(NUM_SPANS)).publishEvent(captor.capture()); + verify(this.publisher, atLeast(this.NUM_SPANS)).publishEvent(captor.capture()); List 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(); + } } - + } } diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/integration/TraceChannelInterceptorTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/integration/TraceChannelInterceptorTests.java index 2100d798e..d8cb15e93 100644 --- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/integration/TraceChannelInterceptorTests.java +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/integration/TraceChannelInterceptorTests.java @@ -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 diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/integration/TraceContextPropagationChannelInterceptorTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/integration/TraceContextPropagationChannelInterceptorTests.java index 3449aff40..deb1a4b1a 100644 --- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/integration/TraceContextPropagationChannelInterceptorTests.java +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/integration/TraceContextPropagationChannelInterceptorTests.java @@ -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); } diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/TraceFilterIntegrationTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/TraceFilterIntegrationTests.java index ea92d8227..4213901a4 100644 --- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/TraceFilterIntegrationTests.java +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/TraceFilterIntegrationTests.java @@ -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()); } diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/TraceFilterTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/TraceFilterTests.java index 85baa7a0a..5d28f3c65 100644 --- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/TraceFilterTests.java +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/TraceFilterTests.java @@ -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)); } } diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/FeignTraceTest.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/FeignTraceTest.java index c499128d8..4d55d52d6 100644 --- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/FeignTraceTest.java +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/FeignTraceTest.java @@ -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 response = testFeignInterface.getNoTrace(); + ResponseEntity 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 response = testFeignInterface.getTraceId(); + ResponseEntity 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 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 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; } diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/TraceRestTemplateInterceptorTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/TraceRestTemplateInterceptorTests.java index 52dbc3519..f043012ef 100644 --- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/TraceRestTemplateInterceptorTests.java +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/TraceRestTemplateInterceptorTests.java @@ -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 - . asList(new TraceRestTemplateInterceptor())); + this.publisher.refresh(); + this.traces = new DefaultTraceManager(new AlwaysSampler(), + new RandomUuidGenerator(), this.publisher); + this.template.setInterceptors(Arrays.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 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 headers = this.template.getForEntity("/", Map.class) - .getBody(); + .getBody(); assertFalse("Wrong headers: " + headers, headers.containsKey(Trace.SPAN_ID_NAME)); } diff --git a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-messaging/src/main/java/sample/SampleBackground.java b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-messaging/src/main/java/sample/SampleBackground.java index 6bcc20fc1..d7d1fa6d7 100644 --- a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-messaging/src/main/java/sample/SampleBackground.java +++ b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-messaging/src/main/java/sample/SampleBackground.java @@ -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)); } } diff --git a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-ribbon/src/main/resources/application.yml b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-ribbon/src/main/resources/application.yml index 156bc7c88..b889b948d 100644 --- a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-ribbon/src/main/resources/application.yml +++ b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-ribbon/src/main/resources/application.yml @@ -1,6 +1,10 @@ server: port: 3382 +sample: + zipkin: + enabled: false + spring: application: name: testSleuthRibbon diff --git a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin/src/main/java/sample/SampleBackground.java b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin/src/main/java/sample/SampleBackground.java index 6bcc20fc1..d7d1fa6d7 100644 --- a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin/src/main/java/sample/SampleBackground.java +++ b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin/src/main/java/sample/SampleBackground.java @@ -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)); } } diff --git a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin/src/main/java/sample/SampleController.java b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin/src/main/java/sample/SampleController.java index dbfabc647..d11659994 100644 --- a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin/src/main/java/sample/SampleController.java +++ b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin/src/main/java/sample/SampleController.java @@ -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 { @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 { 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 { 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 { 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); diff --git a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin/src/main/resources/application.yml b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin/src/main/resources/application.yml index 0987752d1..37a0da4da 100644 --- a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin/src/main/resources/application.yml +++ b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin/src/main/resources/application.yml @@ -11,4 +11,4 @@ logging: sample: zipkin: -# enabled: false \ No newline at end of file + enabled: false \ No newline at end of file diff --git a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample/src/main/java/sample/SampleBackground.java b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample/src/main/java/sample/SampleBackground.java index 6bcc20fc1..d7d1fa6d7 100644 --- a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample/src/main/java/sample/SampleBackground.java +++ b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample/src/main/java/sample/SampleBackground.java @@ -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)); } } diff --git a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample/src/main/java/sample/SampleController.java b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample/src/main/java/sample/SampleController.java index dbfabc647..d2354653e 100644 --- a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample/src/main/java/sample/SampleController.java +++ b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample/src/main/java/sample/SampleController.java @@ -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 { @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 { 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 { @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 { String s = this.restTemplate.getForObject("http://localhost:" + this.port + "/call", String.class); - scope.close(); + this.trace.close(scope); return "traced/" + s; } diff --git a/spring-cloud-sleuth-stream/src/test/java/org/springframework/cloud/sleuth/stream/StreamSpanListenerTests.java b/spring-cloud-sleuth-stream/src/test/java/org/springframework/cloud/sleuth/stream/StreamSpanListenerTests.java index d482be7f8..690db739a 100644 --- a/spring-cloud-sleuth-stream/src/test/java/org/springframework/cloud/sleuth/stream/StreamSpanListenerTests.java +++ b/spring-cloud-sleuth-stream/src/test/java/org/springframework/cloud/sleuth/stream/StreamSpanListenerTests.java @@ -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()); } diff --git a/spring-cloud-sleuth-zipkin/src/test/java/org/springframework/cloud/sleuth/zipkin/ZipkinSpanListenerTests.java b/spring-cloud-sleuth-zipkin/src/test/java/org/springframework/cloud/sleuth/zipkin/ZipkinSpanListenerTests.java index ad5c23178..e7c1cc559 100644 --- a/spring-cloud-sleuth-zipkin/src/test/java/org/springframework/cloud/sleuth/zipkin/ZipkinSpanListenerTests.java +++ b/spring-cloud-sleuth-zipkin/src/test/java/org/springframework/cloud/sleuth/zipkin/ZipkinSpanListenerTests.java @@ -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()); }