diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Span.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Span.java
index 4a152355d..e44e6d44a 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Span.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Span.java
@@ -90,6 +90,7 @@ public class Span {
public static final String SPAN_NOT_SAMPLED = "0";
public static final String SPAN_LOCAL_COMPONENT_TAG_NAME = "lc";
+ public static final String SPAN_ERROR_TAG_NAME = "error";
/**
* cr - Client Receive. Signifies the end of the span. The client has
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceChannelInterceptor.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceChannelInterceptor.java
index a290b5a27..171ab01ad 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceChannelInterceptor.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceChannelInterceptor.java
@@ -23,6 +23,7 @@ import org.springframework.cloud.sleuth.SpanInjector;
import org.springframework.cloud.sleuth.TraceKeys;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.sampler.NeverSampler;
+import org.springframework.cloud.sleuth.util.ExceptionUtils;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
@@ -53,6 +54,7 @@ public class TraceChannelInterceptor extends AbstractTraceChannelInterceptor {
} else if (spanFromHeader != null) {
spanFromHeader.logEvent(Span.CLIENT_RECV);
}
+ addErrorTag(ex);
getTracer().close(spanFromHeader);
}
@@ -120,10 +122,17 @@ public class TraceChannelInterceptor extends AbstractTraceChannelInterceptor {
Span spanFromHeader = getSpanFromHeader(message);
if (spanFromHeader!= null) {
spanFromHeader.logEvent(Span.SERVER_SEND);
+ addErrorTag(ex);
}
getTracer().detach(spanFromHeader);
}
+ private void addErrorTag(Exception ex) {
+ if (ex != null) {
+ getTracer().addTag(Span.SPAN_ERROR_TAG_NAME, ExceptionUtils.getExceptionMessage(ex));
+ }
+ }
+
private Span getSpanFromHeader(Message> message) {
if (message == null) {
return null;
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 f8ba27379..96ed118a7 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
@@ -36,6 +36,7 @@ import org.springframework.cloud.sleuth.SpanReporter;
import org.springframework.cloud.sleuth.TraceKeys;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.sampler.NeverSampler;
+import org.springframework.cloud.sleuth.util.ExceptionUtils;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
@@ -140,6 +141,7 @@ public class TraceFilter extends GenericFilterBean {
filterChain.doFilter(request, response);
} catch (Throwable e) {
exception = e;
+ this.tracer.addTag(Span.SPAN_ERROR_TAG_NAME, ExceptionUtils.getExceptionMessage(e));
throw e;
} finally {
if (isAsyncStarted(request) || request.isAsyncStarted()) {
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 58bc9a4b1..538195de3 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
@@ -27,6 +27,7 @@ import org.springframework.boot.autoconfigure.web.ErrorController;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.TraceKeys;
import org.springframework.cloud.sleuth.Tracer;
+import org.springframework.cloud.sleuth.util.ExceptionUtils;
import org.springframework.cloud.sleuth.util.SpanNameUtil;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
@@ -150,6 +151,9 @@ public class TraceHandlerInterceptor extends HandlerInterceptorAdapter {
if (log.isDebugEnabled()) {
log.debug("Closing span " + span);
}
+ if (ex != null) {
+ getTracer().addTag(Span.SPAN_ERROR_TAG_NAME, ExceptionUtils.getExceptionMessage(ex));
+ }
getTracer().close(span);
}
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 8eda2fbc4..ce71beb84 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
@@ -18,9 +18,11 @@ package org.springframework.cloud.sleuth.instrument.web.client;
import java.io.IOException;
+import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanInjector;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.instrument.web.HttpTraceKeysInjector;
+import org.springframework.cloud.sleuth.util.ExceptionUtils;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
@@ -59,6 +61,7 @@ public class TraceRestTemplateInterceptor extends AbstractTraceHttpRequestInterc
if (log.isDebugEnabled()) {
log.debug("Exception occurred while trying to execute the request. Will close the span [" + currentSpan() + "]", e);
}
+ this.tracer.addTag(Span.SPAN_ERROR_TAG_NAME, ExceptionUtils.getExceptionMessage(e));
this.tracer.close(currentSpan());
throw e;
}
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/feign/TraceFeignClient.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/feign/TraceFeignClient.java
index 1c66c0108..33acce88b 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/feign/TraceFeignClient.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/feign/TraceFeignClient.java
@@ -31,6 +31,7 @@ import org.springframework.cloud.sleuth.instrument.web.HttpTraceKeysInjector;
import feign.Client;
import feign.Request;
import feign.Response;
+import org.springframework.cloud.sleuth.util.ExceptionUtils;
/**
* A Feign Client that closes a Span if there is no response body. In other cases Span
@@ -134,11 +135,7 @@ class TraceFeignClient implements Client {
private void logError(Exception e) {
Span span = getTracer().getCurrentSpan();
if (span != null) {
- String message = e.getMessage() != null ? e.getMessage() : e.toString();
- if (log.isDebugEnabled()) {
- log.debug("Appending exception [" + message + "] to span " + span);
- }
- getTracer().addTag("error", message);
+ getTracer().addTag(Span.SPAN_ERROR_TAG_NAME, ExceptionUtils.getExceptionMessage(e));
}
}
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/util/ExceptionUtils.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/util/ExceptionUtils.java
index 7cabe94a8..2c0182a20 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/util/ExceptionUtils.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/util/ExceptionUtils.java
@@ -55,4 +55,8 @@ public final class ExceptionUtils {
ExceptionUtils.fail = fail;
ExceptionUtils.lastException = null;
}
+
+ public static String getExceptionMessage(Throwable e) {
+ return e.getMessage() != null ? e.getMessage() : e.toString();
+ }
}
diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/async/issues/issue410/Issue410Tests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/async/issues/issue410/Issue410Tests.java
index cf180ca1b..dd3c17a08 100644
--- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/async/issues/issue410/Issue410Tests.java
+++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/async/issues/issue410/Issue410Tests.java
@@ -71,27 +71,33 @@ public class Issue410Tests {
@Test
public void should_pass_tracing_info_for_tasks_running_without_a_pool() {
Span span = this.tracer.createSpan("foo");
+ try {
+ String response = this.restTemplate.getForObject("http://localhost:" + port() + "/without_pool", String.class);
- String response = this.restTemplate.getForObject("http://localhost:" + port() + "/without_pool", String.class);
-
- then(response).isEqualTo(Span.idToHex(span.getTraceId()));
- Awaitility.await().until(() -> {
- then(this.asyncTask.getSpan().get()).isNotNull();
- then(this.asyncTask.getSpan().get().getTraceId()).isEqualTo(span.getTraceId());
- });
+ then(response).isEqualTo(Span.idToHex(span.getTraceId()));
+ Awaitility.await().until(() -> {
+ then(this.asyncTask.getSpan().get()).isNotNull();
+ then(this.asyncTask.getSpan().get().getTraceId()).isEqualTo(span.getTraceId());
+ });
+ } finally {
+ this.tracer.close(span);
+ }
}
@Test
public void should_pass_tracing_info_for_tasks_running_with_a_pool() {
Span span = this.tracer.createSpan("foo");
+ try {
+ String response = this.restTemplate.getForObject("http://localhost:" + port() + "/with_pool", String.class);
- String response = this.restTemplate.getForObject("http://localhost:" + port() + "/with_pool", String.class);
-
- then(response).isEqualTo(Span.idToHex(span.getTraceId()));
- Awaitility.await().until(() -> {
- then(this.asyncTask.getSpan().get()).isNotNull();
- then(this.asyncTask.getSpan().get().getTraceId()).isEqualTo(span.getTraceId());
- });
+ then(response).isEqualTo(Span.idToHex(span.getTraceId()));
+ Awaitility.await().until(() -> {
+ then(this.asyncTask.getSpan().get()).isNotNull();
+ then(this.asyncTask.getSpan().get().getTraceId()).isEqualTo(span.getTraceId());
+ });
+ } finally {
+ this.tracer.close(span);
+ }
}
/**
@@ -100,14 +106,17 @@ public class Issue410Tests {
@Test
public void should_pass_tracing_info_for_completable_futures_with_executor() {
Span span = this.tracer.createSpan("foo");
+ try {
+ String response = this.restTemplate.getForObject("http://localhost:" + port() + "/completable", String.class);
- String response = this.restTemplate.getForObject("http://localhost:" + port() + "/completable", String.class);
-
- then(response).isEqualTo(Span.idToHex(span.getTraceId()));
- Awaitility.await().until(() -> {
- then(this.asyncTask.getSpan().get()).isNotNull();
- then(this.asyncTask.getSpan().get().getTraceId()).isEqualTo(span.getTraceId());
- });
+ then(response).isEqualTo(Span.idToHex(span.getTraceId()));
+ Awaitility.await().until(() -> {
+ then(this.asyncTask.getSpan().get()).isNotNull();
+ then(this.asyncTask.getSpan().get().getTraceId()).isEqualTo(span.getTraceId());
+ });
+ } finally {
+ this.tracer.close(span);
+ }
}
/**
@@ -116,14 +125,17 @@ public class Issue410Tests {
@Test
public void should_pass_tracing_info_for_completable_futures_with_task_scheduler() {
Span span = this.tracer.createSpan("foo");
+ try {
+ String response = this.restTemplate.getForObject("http://localhost:" + port() + "/taskScheduler", String.class);
- String response = this.restTemplate.getForObject("http://localhost:" + port() + "/taskScheduler", String.class);
-
- then(response).isEqualTo(Span.idToHex(span.getTraceId()));
- Awaitility.await().until(() -> {
- then(this.asyncTask.getSpan().get()).isNotNull();
- then(this.asyncTask.getSpan().get().getTraceId()).isEqualTo(span.getTraceId());
- });
+ then(response).isEqualTo(Span.idToHex(span.getTraceId()));
+ Awaitility.await().until(() -> {
+ then(this.asyncTask.getSpan().get()).isNotNull();
+ then(this.asyncTask.getSpan().get().getTraceId()).isEqualTo(span.getTraceId());
+ });
+ } finally {
+ this.tracer.close(span);
+ }
}
private int port() {
diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/messaging/TraceChannelInterceptorTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/messaging/TraceChannelInterceptorTests.java
index 3881f5e06..f01752ce3 100644
--- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/messaging/TraceChannelInterceptorTests.java
+++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/messaging/TraceChannelInterceptorTests.java
@@ -35,6 +35,7 @@ import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.cloud.sleuth.Sampler;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
+import org.springframework.cloud.sleuth.assertions.ListOfSpans;
import org.springframework.cloud.sleuth.assertions.SleuthAssertions;
import org.springframework.cloud.sleuth.instrument.messaging.TraceChannelInterceptorTests.App;
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
@@ -88,7 +89,7 @@ public class TraceChannelInterceptorTests implements MessageHandler {
this.message = message;
this.span = TestSpanContextHolder.getCurrentSpan();
if (message.getHeaders().containsKey("THROW_EXCEPTION")) {
- throw new RuntimeException();
+ throw new RuntimeException("A terrible exception has occurred");
}
}
@@ -269,6 +270,9 @@ public class TraceChannelInterceptorTests implements MessageHandler {
then(this.message).isNotNull();
this.tracer.close(span);
then(TestSpanContextHolder.getCurrentSpan()).isNull();
+ then(new ListOfSpans(this.accumulator.getSpans()))
+ .hasASpanWithTagEqualTo(Span.SPAN_ERROR_TAG_NAME,
+ "A terrible exception has occurred");
}
@Test
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 a06f90198..db7a6a213 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
@@ -33,6 +33,7 @@ import org.springframework.cloud.sleuth.SpanExtractor;
import org.springframework.cloud.sleuth.SpanReporter;
import org.springframework.cloud.sleuth.TraceKeys;
import org.springframework.cloud.sleuth.Tracer;
+import org.springframework.cloud.sleuth.assertions.ListOfSpans;
import org.springframework.cloud.sleuth.log.SpanLogger;
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
import org.springframework.cloud.sleuth.sampler.NeverSampler;
@@ -287,7 +288,7 @@ public class TraceFilterTests {
}
@Test
- public void catchesException() throws Exception {
+ public void shouldAnnotateSpanWithErrorWhenExceptionIsThrown() throws Exception {
this.request = builder().header(Span.SPAN_ID_NAME, PARENT_ID)
.header(Span.TRACE_ID_NAME, 20L).buildRequest(new MockServletContext());
TraceFilter filter = new TraceFilter(this.tracer, this.traceKeys, this.spanReporter,
@@ -298,7 +299,7 @@ public class TraceFilterTests {
javax.servlet.ServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
throw new RuntimeException("Planned");
- };
+ }
};
try {
filter.doFilter(this.request, this.response, this.filterChain);
@@ -309,6 +310,8 @@ public class TraceFilterTests {
verifyParentSpanHttpTags(HttpStatus.INTERNAL_SERVER_ERROR);
then(TestSpanContextHolder.getCurrentSpan()).isNull();
+ then(new ListOfSpans(this.spanReporter.getSpans()))
+ .hasASpanWithTagEqualTo(Span.SPAN_ERROR_TAG_NAME, "Planned");
}
@Test
diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/TraceFilterWebIntegrationTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/TraceFilterWebIntegrationTests.java
index 10a98f72b..a8df68a98 100644
--- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/TraceFilterWebIntegrationTests.java
+++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/TraceFilterWebIntegrationTests.java
@@ -26,6 +26,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.sleuth.Sampler;
+import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.assertions.ListOfSpans;
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
@@ -73,6 +74,9 @@ public class TraceFilterWebIntegrationTests {
.doesNotHaveASpanWithName("error")
.hasASpanWithTagEqualTo("http.status_code", "500");
then(ExceptionUtils.getLastException()).isNull();
+ then(new ListOfSpans(this.accumulator.getSpans()))
+ .hasASpanWithTagEqualTo(Span.SPAN_ERROR_TAG_NAME,
+ "Request processing failed; nested exception is java.lang.RuntimeException: Throwing exception");
}
private int port() {
diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/TraceRestTemplateInterceptorIntegrationTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/TraceRestTemplateInterceptorIntegrationTests.java
index 48c4e662e..73a363ecc 100644
--- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/TraceRestTemplateInterceptorIntegrationTests.java
+++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/TraceRestTemplateInterceptorIntegrationTests.java
@@ -27,15 +27,16 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.cloud.sleuth.DefaultSpanNamer;
-import org.springframework.cloud.sleuth.NoOpSpanReporter;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.TraceKeys;
+import org.springframework.cloud.sleuth.assertions.ListOfSpans;
import org.springframework.cloud.sleuth.assertions.SleuthAssertions;
import org.springframework.cloud.sleuth.instrument.web.HttpTraceKeysInjector;
import org.springframework.cloud.sleuth.log.NoOpSpanLogger;
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
import org.springframework.cloud.sleuth.trace.DefaultTracer;
import org.springframework.cloud.sleuth.trace.TestSpanContextHolder;
+import org.springframework.cloud.sleuth.util.ArrayListSpanAccumulator;
import org.springframework.cloud.sleuth.util.ExceptionUtils;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpRequestInterceptor;
@@ -59,10 +60,12 @@ public class TraceRestTemplateInterceptorIntegrationTests {
private DefaultTracer tracer;
+ private ArrayListSpanAccumulator spanAccumulator = new ArrayListSpanAccumulator();
+
@Before
public void setup() {
this.tracer = new DefaultTracer(new AlwaysSampler(), new Random(),
- new DefaultSpanNamer(), new NoOpSpanLogger(), new NoOpSpanReporter());
+ new DefaultSpanNamer(), new NoOpSpanLogger(), this.spanAccumulator);
this.template.setInterceptors(Arrays.asList(
new TraceRestTemplateInterceptor(this.tracer, new HttpRequestInjector(),
new HttpTraceKeysInjector(this.tracer, new TraceKeys()))));
@@ -91,6 +94,9 @@ public class TraceRestTemplateInterceptorIntegrationTests {
SleuthAssertions.then(this.tracer.getCurrentSpan()).isEqualTo(span);
this.tracer.close(span);
+ SleuthAssertions.then(new ListOfSpans(this.spanAccumulator.getSpans()))
+ .hasASpanWithTagEqualTo(Span.SPAN_ERROR_TAG_NAME,
+ "Read timed out");
then(ExceptionUtils.getLastException()).isNull();
}
diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/feign/TraceFeignClientTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/feign/TraceFeignClientTests.java
index 1477bd2ce..ce8f7ea21 100644
--- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/feign/TraceFeignClientTests.java
+++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/feign/TraceFeignClientTests.java
@@ -99,7 +99,7 @@ public class TraceFeignClientTests {
then(this.tracer.getCurrentSpan()).isEqualTo(span);
then(this.spanAccumulator.getSpans().get(0))
.hasNotLoggedAnEvent(Span.CLIENT_RECV)
- .hasATag("error", "exception has occurred");
+ .hasATag(Span.SPAN_ERROR_TAG_NAME, "exception has occurred");
}
}
\ No newline at end of file
diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/feign/servererrors/FeignClientServerErrorTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/feign/servererrors/FeignClientServerErrorTests.java
index fd58109b8..6848ff21d 100644
--- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/feign/servererrors/FeignClientServerErrorTests.java
+++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/feign/servererrors/FeignClientServerErrorTests.java
@@ -38,6 +38,7 @@ import org.springframework.cloud.sleuth.Sampler;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanReporter;
import org.springframework.cloud.sleuth.Tracer;
+import org.springframework.cloud.sleuth.assertions.ListOfSpans;
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
import org.springframework.cloud.sleuth.util.ExceptionUtils;
import org.springframework.context.annotation.Bean;
@@ -53,6 +54,7 @@ import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
+import com.jayway.awaitility.Awaitility;
import com.netflix.hystrix.exception.HystrixRuntimeException;
import com.netflix.loadbalancer.BaseLoadBalancer;
import com.netflix.loadbalancer.ILoadBalancer;
@@ -61,7 +63,7 @@ import com.netflix.loadbalancer.Server;
import feign.codec.Decoder;
import feign.codec.ErrorDecoder;
-import static org.assertj.core.api.BDDAssertions.then;
+import static org.springframework.cloud.sleuth.assertions.SleuthAssertions.then;
/**
* Related to https://github.com/spring-cloud/spring-cloud-sleuth/issues/257
@@ -76,10 +78,12 @@ public class FeignClientServerErrorTests {
@Autowired TestFeignInterface feignInterface;
@Autowired TestFeignWithCustomConfInterface customConfFeignInterface;
+ @Autowired Listener listener;
@Rule public OutputCapture capture = new OutputCapture();
@Before
public void setup() {
+ this.listener.clear();
ExceptionUtils.setFail(true);
}
@@ -90,11 +94,17 @@ public class FeignClientServerErrorTests {
} catch (HystrixRuntimeException e) {
}
- // ugly :/ waiting for rx thread to complete
- Thread.sleep(100);
- then(this.capture.toString())
- .doesNotContain("Tried to close span but it is not the current span");
- then(ExceptionUtils.getLastException()).isNull();
+ Awaitility.await().until(() -> {
+ then(this.capture.toString())
+ .doesNotContain("Tried to close span but it is not the current span");
+ then(ExceptionUtils.getLastException()).isNull();
+ then(new ListOfSpans(this.listener.getEvents()))
+ .hasASpanWithTagEqualTo(Span.SPAN_ERROR_TAG_NAME,
+ "Request processing failed; nested exception is java.lang.RuntimeException: Internal Error");
+ then(new ListOfSpans(this.listener.getEvents()))
+ .hasASpanWithTagEqualTo(Span.SPAN_ERROR_TAG_NAME,
+ "Internal Error");
+ });
}
@Test
@@ -104,11 +114,11 @@ public class FeignClientServerErrorTests {
} catch (HystrixRuntimeException e) {
}
- // ugly :/ waiting for rx thread to complete
- Thread.sleep(100);
- then(this.capture.toString())
- .doesNotContain("Tried to close span but it is not the current span");
- then(ExceptionUtils.getLastException()).isNull();
+ Awaitility.await().until(() -> {
+ then(this.capture.toString())
+ .doesNotContain("Tried to close span but it is not the current span");
+ then(ExceptionUtils.getLastException()).isNull();
+ });
}
@Test
@@ -118,11 +128,10 @@ public class FeignClientServerErrorTests {
} catch (HystrixRuntimeException e) {
}
- // ugly :/ waiting for rx thread to complete
- Thread.sleep(100);
- then(this.capture.toString())
- .doesNotContain("Tried to close span but it is not the current span");
- then(ExceptionUtils.getLastException()).isNull();
+ Awaitility.await().until(() -> {
+ then(this.capture.toString()).doesNotContain("Tried to close span but it is not the current span");
+ then(ExceptionUtils.getLastException()).isNull();
+ });
}
@Test
@@ -132,11 +141,10 @@ public class FeignClientServerErrorTests {
} catch (HystrixRuntimeException e) {
}
- // ugly :/ waiting for rx thread to complete
- Thread.sleep(100);
- then(this.capture.toString())
- .doesNotContain("Tried to close span but it is not the current span");
- then(ExceptionUtils.getLastException()).isNull();
+ Awaitility.await().until(() -> {
+ then(this.capture.toString()).doesNotContain("Tried to close span but it is not the current span");
+ then(ExceptionUtils.getLastException()).isNull();
+ });
}
@Test
@@ -146,11 +154,10 @@ public class FeignClientServerErrorTests {
} catch (HystrixRuntimeException e) {
}
- // ugly :/ waiting for rx thread to complete
- Thread.sleep(100);
- then(this.capture.toString())
- .doesNotContain("Tried to close span but it is not the current span");
- then(ExceptionUtils.getLastException()).isNull();
+ Awaitility.await().until(() -> {
+ then(this.capture.toString()).doesNotContain("Tried to close span but it is not the current span");
+ then(ExceptionUtils.getLastException()).isNull();
+ });
}
@Configuration
@@ -226,7 +233,11 @@ public class FeignClientServerErrorTests {
private List events = new ArrayList<>();
public List getEvents() {
- return this.events;
+ return new ArrayList<>(this.events);
+ }
+
+ public void clear() {
+ this.events.clear();
}
@Override
@@ -246,8 +257,7 @@ public class FeignClientServerErrorTests {
@RequestHeader(Span.TRACE_ID_NAME) String traceId,
@RequestHeader(Span.SPAN_ID_NAME) String spanId,
@RequestHeader(Span.PARENT_ID_NAME) String parentId) {
- return new ResponseEntity<>("internal error",
- HttpStatus.INTERNAL_SERVER_ERROR);
+ throw new RuntimeException("Internal Error");
}
@RequestMapping("/notfound")
diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/util/ExceptionUtilsTest.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/util/ExceptionUtilsTest.java
index 7820dd83f..13da88cc6 100644
--- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/util/ExceptionUtilsTest.java
+++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/util/ExceptionUtilsTest.java
@@ -50,4 +50,22 @@ public class ExceptionUtilsTest {
then(e).isInstanceOf(IllegalStateException.class);
}
}
+
+ @Test
+ public void should_print_error_message_when_there_is_one() throws Exception {
+ Throwable e = new RuntimeException("Foo");
+
+ String message = ExceptionUtils.getExceptionMessage(e);
+
+ then(message).isEqualTo("Foo");
+ }
+
+ @Test
+ public void should_print_to_string_when_there_is_no_error() throws Exception {
+ Throwable e = new RuntimeException();
+
+ String message = ExceptionUtils.getExceptionMessage(e);
+
+ then(message).isEqualTo("java.lang.RuntimeException");
+ }
}
\ No newline at end of file