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 22c3f51a4..ee991dd52 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 @@ -69,6 +69,12 @@ public class TraceSchedulingAspect { span.tag(METHOD_KEY, pjp.getSignature().getName()); return pjp.proceed(); } + catch (Throwable ex) { + String message = ex.getMessage() == null ? ex.getClass().getSimpleName() + : ex.getMessage(); + span.tag("error", message); + throw ex; + } finally { span.finish(); } 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 dbc2e963b..d0356f8ee 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 @@ -103,7 +103,8 @@ public class TraceWebAutoConfiguration { } @Configuration - @ConditionalOnClass({ ServerProperties.class, EndpointsSupplier.class, ExposableWebEndpoint.class }) + @ConditionalOnClass({ ServerProperties.class, EndpointsSupplier.class, + ExposableWebEndpoint.class }) @ConditionalOnBean(ServerProperties.class) @ConditionalOnProperty(value = "spring.sleuth.web.ignoreAutoConfiguredSkipPatterns", havingValue = "false", matchIfMissing = true) protected static class ActuatorSkipPatternProviderConfig { @@ -146,10 +147,11 @@ public class TraceWebAutoConfiguration { final ServerProperties serverProperties, final WebEndpointProperties webEndpointProperties, final EndpointsSupplier endpointsSupplier) { - return () -> getEndpointsPatterns(serverProperties.getServlet().getContextPath(), - webEndpointProperties, endpointsSupplier); + return () -> getEndpointsPatterns( + serverProperties.getServlet().getContextPath(), webEndpointProperties, + endpointsSupplier); } - + @Bean @ConditionalOnManagementPort(ManagementPortType.DIFFERENT) @ConditionalOnProperty(name = "management.server.servlet.context-path", havingValue = "/", matchIfMissing = true) @@ -157,8 +159,10 @@ public class TraceWebAutoConfiguration { final ServerProperties serverProperties, final WebEndpointProperties webEndpointProperties, final EndpointsSupplier endpointsSupplier) { - return () -> getEndpointsPatterns(null, webEndpointProperties, endpointsSupplier); + return () -> getEndpointsPatterns(null, webEndpointProperties, + endpointsSupplier); } + } @Configuration diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/scheduling/TracingOnScheduledTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/scheduling/TracingOnScheduledTests.java index 50f4db38e..a3f09a78d 100644 --- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/scheduling/TracingOnScheduledTests.java +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/scheduling/TracingOnScheduledTests.java @@ -55,6 +55,9 @@ public class TracingOnScheduledTests { @Autowired TestBeanWithScheduledMethodToBeIgnored beanWithScheduledMethodToBeIgnored; + @Autowired + TestBeanWithScheduledMethodThatThrowsAnException throwsAnException; + @Autowired ArrayListSpanReporter reporter; @@ -72,6 +75,14 @@ public class TracingOnScheduledTests { }); } + @Test + public void should_have_span_set_with_error_tag() { + await().atMost(10, SECONDS).untilAsserted(() -> { + then(this.throwsAnException.isExecuted()).isTrue(); + spanIsSetOnAScheduledMethodWithErrorTag(); + }); + } + @Test public void should_have_a_new_span_set_each_time_a_scheduled_method_has_been_executed() { final Span firstSpan = this.beanWithScheduledMethod.getSpan(); @@ -94,10 +105,28 @@ public class TracingOnScheduledTests { Span storedSpan = TracingOnScheduledTests.this.beanWithScheduledMethod.getSpan(); then(storedSpan).isNotNull(); then(storedSpan.context().traceId()).isNotNull(); - then(this.reporter.getSpans().get(0).tags()).contains( + zipkin2.Span foundSpan = this.reporter.getSpans().stream() + .filter(span -> !span.tags().containsKey("error")).findFirst() + .orElseThrow(() -> new AssertionError("Span is missing")); + then(foundSpan.tags()).contains( new AbstractMap.SimpleEntry<>("class", "TestBeanWithScheduledMethod"), new AbstractMap.SimpleEntry<>("method", "scheduledMethod")); - then(this.reporter.getSpans().get(0).durationAsLong()).isGreaterThan(0L); + then(foundSpan.durationAsLong()).isGreaterThan(0L); + } + + private void spanIsSetOnAScheduledMethodWithErrorTag() { + Span storedSpan = TracingOnScheduledTests.this.beanWithScheduledMethod.getSpan(); + then(storedSpan).isNotNull(); + then(storedSpan.context().traceId()).isNotNull(); + zipkin2.Span foundSpan = this.reporter.getSpans().stream() + .filter(span -> span.tags().containsKey("error")).findFirst() + .orElseThrow(() -> new AssertionError("Span is missing")); + then(foundSpan.tags()).contains( + new AbstractMap.SimpleEntry<>("class", + "TestBeanWithScheduledMethodThatThrowsAnException"), + new AbstractMap.SimpleEntry<>("method", "scheduledMethod")); + then(foundSpan.durationAsLong()).isGreaterThan(0L); + then(foundSpan.tags().get("error")).isNotEmpty(); } private void differentSpanHasBeenSetThan(final Span spanToCompare) { @@ -128,6 +157,11 @@ class ScheduledTestConfiguration { return new TestBeanWithScheduledMethodToBeIgnored(tracing); } + @Bean + TestBeanWithScheduledMethodThatThrowsAnException throwsAnException(Tracing tracing) { + return new TestBeanWithScheduledMethodThatThrowsAnException(tracing); + } + @Bean Sampler alwaysSampler() { return Sampler.ALWAYS_SAMPLE; @@ -172,6 +206,44 @@ class TestBeanWithScheduledMethod { } +class TestBeanWithScheduledMethodThatThrowsAnException { + + private static final Log log = LogFactory.getLog(TestBeanWithScheduledMethod.class); + + private final Tracing tracing; + + Span span; + + AtomicBoolean executed = new AtomicBoolean(false); + + TestBeanWithScheduledMethodThatThrowsAnException(Tracing tracing) { + this.tracing = tracing; + } + + @Scheduled(fixedDelay = 1L) + public void scheduledMethod() { + log.info("Running the scheduled method"); + this.span = this.tracing.tracer().currentSpan(); + log.info("Stored the span " + this.span + " as current span"); + this.executed.set(true); + throw new RuntimeException("HELLO"); + } + + public Span getSpan() { + return this.span; + } + + public AtomicBoolean isExecuted() { + return this.executed; + } + + public void clear() { + this.span = null; + this.executed.set(false); + } + +} + class TestBeanWithScheduledMethodToBeIgnored { private final Tracing tracing;