diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/feign/FeignRequestInjector.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/feign/FeignRequestInjector.java new file mode 100644 index 000000000..20c6da8ef --- /dev/null +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/feign/FeignRequestInjector.java @@ -0,0 +1,79 @@ +/* + * Copyright 2013-2017 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.instrument.web.client.feign; + +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; + +import org.springframework.cloud.sleuth.Span; +import org.springframework.cloud.sleuth.SpanInjector; +import org.springframework.util.StringUtils; + +import feign.Request; + +/** + * Span injector that injects tracing info to {@link Request} via {@link AtomicReference} + * since {@link Request} is immutable. + * + * @author Marcin Grzejszczak + * + * @since 1.0.0 + */ +class FeignRequestInjector implements SpanInjector> { + + @Override + public void inject(Span span, AtomicReference carrier) { + String method = carrier.get().method(); + String url = carrier.get().url(); + Map> headers = new HashMap<>(carrier.get().headers()); + byte[] body = carrier.get().body(); + Charset charset = carrier.get().charset(); + if (span == null) { + setHeader(headers, Span.SAMPLED_NAME, Span.SPAN_NOT_SAMPLED); + carrier.set(Request.create(method, url, headers, body, charset)); + return; + } + setHeader(headers, Span.TRACE_ID_NAME, Span.idToHex(span.getTraceId())); + setHeader(headers, Span.SPAN_NAME_NAME, span.getName()); + setHeader(headers, Span.SPAN_ID_NAME, Span.idToHex(span.getSpanId())); + setHeader(headers, Span.SAMPLED_NAME, span.isExportable() ? + Span.SPAN_SAMPLED : Span.SPAN_NOT_SAMPLED); + Long parentId = getParentId(span); + if (parentId != null) { + setHeader(headers, Span.PARENT_ID_NAME, Span.idToHex(parentId)); + } + setHeader(headers, Span.PROCESS_ID_NAME, span.getProcessId()); + carrier.set(Request.create(method, url, headers, body, charset)); + } + + private Long getParentId(Span span) { + return !span.getParents().isEmpty() ? span.getParents().get(0) : null; + } + + protected void setHeader(Map> headers, String name, String value) { + if (StringUtils.hasText(value) && !headers.containsKey(name)) { + List list = new ArrayList<>(); + list.add(value); + headers.put(name, list); + } + } +} diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/feign/NeverRetry.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/feign/NeverRetry.java new file mode 100644 index 000000000..72753c713 --- /dev/null +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/feign/NeverRetry.java @@ -0,0 +1,23 @@ +package org.springframework.cloud.sleuth.instrument.web.client.feign; + +import feign.RetryableException; +import feign.Retryer; + +/** + * This is essentially the same implementation of a Retryer that is in newer versions of + * Feign. For the 1.0.x stream we add it here. + * @author Ryan Baxter + */ +public class NeverRetry implements Retryer { + @Override + public void continueOrPropagate(RetryableException e) { + throw e; + } + + @Override + public Retryer clone() { + return this; + } + + public static final NeverRetry INSTANCE = new NeverRetry(); +} diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/log/Slf4jSpanLogger.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/log/Slf4jSpanLogger.java index f67235ca2..ecc1e41bd 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/log/Slf4jSpanLogger.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/log/Slf4jSpanLogger.java @@ -23,8 +23,7 @@ import org.slf4j.MDC; import org.springframework.cloud.sleuth.Span; /** - * Span listener that logs to the console when a span got - * started / stopped / continued. + * Span listener that logs to the console when a span got started / stopped / continued. * * @author Spencer Gibb * @since 1.0.0 @@ -36,8 +35,7 @@ public class Slf4jSpanLogger implements SpanLogger { public Slf4jSpanLogger(String nameSkipPattern) { this.nameSkipPattern = Pattern.compile(nameSkipPattern); - this.log = org.slf4j.LoggerFactory - .getLogger(Slf4jSpanLogger.class); + this.log = org.slf4j.LoggerFactory.getLogger(Slf4jSpanLogger.class); } Slf4jSpanLogger(String nameSkipPattern, Logger log) { @@ -74,7 +72,9 @@ public class Slf4jSpanLogger implements SpanLogger { @Override public void logStoppedSpan(Span parent, Span span) { - log("Stopped span: {}", span); + if (span != null) { + log("Stopped span: {}", span); + } if (span != null && parent != null) { log("With parent: {}", parent); MDC.put(Span.SPAN_ID_NAME, Span.idToHex(parent.getSpanId())); diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/autoconfig/TraceAutoConfigurationTest.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/autoconfig/TraceAutoConfigurationTest.java new file mode 100644 index 000000000..e69de29bb diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/hystrix/TraceCommandTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/hystrix/TraceCommandTests.java index 57722eaf6..f3eb52910 100644 --- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/hystrix/TraceCommandTests.java +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/hystrix/TraceCommandTests.java @@ -39,7 +39,6 @@ import com.netflix.hystrix.strategy.HystrixPlugins; import static com.netflix.hystrix.HystrixCommand.Setter.withGroupKey; import static com.netflix.hystrix.HystrixCommandGroupKey.Factory.asKey; -import static org.assertj.core.api.BDDAssertions.then; import static org.springframework.cloud.sleuth.assertions.SleuthAssertions.then; public class TraceCommandTests { 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 feb03c1ea..c8f470790 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 @@ -37,7 +37,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.request.async.DeferredResult; -import static org.assertj.core.api.BDDAssertions.then; import static org.springframework.cloud.sleuth.assertions.SleuthAssertions.then; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;