Spring Cloud Circuit Breaker tracing (#1505)
Adds support for Spring Cloud CircuitBreaker
This commit is contained in:
committed by
GitHub
parent
bc640791ab
commit
11c8090b94
@@ -1083,6 +1083,11 @@ include::{project-root}/spring-cloud-sleuth-core/src/test/java/org/springframewo
|
||||
|
||||
That way, you ensure that a new span is created and closed for each execution.
|
||||
|
||||
=== Spring Cloud CircuitBreaker
|
||||
|
||||
If you have Spring Cloud CircuitBreaker on the classpath, we will wrap the passed command `Supplier` and the fallback `Function` in its trace representations. In order to disable this instrumentation set `spring.sleuth.circuitbreaker.enabled` to `false`.
|
||||
|
||||
|
||||
=== Hystrix
|
||||
|
||||
==== Custom Concurrency Strategy
|
||||
|
||||
8
pom.xml
8
pom.xml
@@ -176,6 +176,13 @@
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-circuitbreaker-dependencies</artifactId>
|
||||
<version>${spring-cloud-circuitbreaker.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-stream-dependencies</artifactId>
|
||||
@@ -255,6 +262,7 @@
|
||||
<spring-cloud-build.version>2.2.1.BUILD-SNAPSHOT</spring-cloud-build.version>
|
||||
<spring-cloud-commons.version>2.2.1.BUILD-SNAPSHOT</spring-cloud-commons.version>
|
||||
<spring-cloud-gateway.version>2.2.1.BUILD-SNAPSHOT</spring-cloud-gateway.version>
|
||||
<spring-cloud-circuitbreaker.version>1.0.1.BUILD-SNAPSHOT</spring-cloud-circuitbreaker.version>
|
||||
<spring-cloud-stream.version>Horsham.RELEASE</spring-cloud-stream.version>
|
||||
<spring-cloud-netflix.version>2.2.1.BUILD-SNAPSHOT</spring-cloud-netflix.version>
|
||||
<spring-cloud-openfeign.version>2.2.1.BUILD-SNAPSHOT</spring-cloud-openfeign.version>
|
||||
|
||||
@@ -95,6 +95,11 @@
|
||||
<artifactId>spring-cloud-starter-gateway</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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
|
||||
*
|
||||
* https://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.circuitbreaker;
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import brave.Tracer;
|
||||
import brave.Tracing;
|
||||
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.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.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.client.circuitbreaker.CircuitBreaker;
|
||||
import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* Auto-configuration} that registers instrumentation for circuit breakers.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 2.2.1
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@AutoConfigureAfter(TraceAutoConfiguration.class)
|
||||
@ConditionalOnClass(CircuitBreaker.class)
|
||||
@ConditionalOnBean(Tracing.class)
|
||||
@ConditionalOnProperty(value = "spring.sleuth.circuitbreaker.enabled",
|
||||
matchIfMissing = true)
|
||||
@EnableConfigurationProperties(SleuthCircuitBreakerProperties.class)
|
||||
public class SleuthCircuitBreakerAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
TraceCircuitBreakerFactoryAspect traceCircuitBreakerFactoryAspect(Tracer tracer) {
|
||||
return new TraceCircuitBreakerFactoryAspect(tracer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Aspect
|
||||
class TraceCircuitBreakerFactoryAspect {
|
||||
|
||||
private final Tracer tracer;
|
||||
|
||||
TraceCircuitBreakerFactoryAspect(Tracer tracer) {
|
||||
this.tracer = tracer;
|
||||
}
|
||||
|
||||
@Pointcut("execution(public * org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory.create(..))")
|
||||
private void anyCircuitBreakerFactoryCreate() {
|
||||
} // NOSONAR
|
||||
|
||||
@Around("anyCircuitBreakerFactoryCreate()")
|
||||
public Object wrapFactory(ProceedingJoinPoint pjp) throws Throwable {
|
||||
CircuitBreaker circuitBreaker = (CircuitBreaker) pjp.proceed();
|
||||
return new TraceCircuitBreaker(circuitBreaker, this.tracer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class TraceCircuitBreaker implements CircuitBreaker {
|
||||
|
||||
private final CircuitBreaker delegate;
|
||||
|
||||
private final Tracer tracer;
|
||||
|
||||
TraceCircuitBreaker(CircuitBreaker delegate, Tracer tracer) {
|
||||
this.delegate = delegate;
|
||||
this.tracer = tracer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T run(Supplier<T> toRun, Function<Throwable, T> fallback) {
|
||||
return this.delegate.run(new TraceSupplier<>(this.tracer, toRun),
|
||||
new TraceFunction<>(this.tracer, fallback));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T run(Supplier<T> toRun) {
|
||||
return this.delegate.run(new TraceSupplier<>(this.tracer, toRun));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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
|
||||
*
|
||||
* https://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.circuitbreaker;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Sleuth Circuit Breaker settings.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 2.2.1
|
||||
*/
|
||||
@ConfigurationProperties("spring.sleuth.circuitbreaker")
|
||||
public class SleuthCircuitBreakerProperties {
|
||||
|
||||
/**
|
||||
* Enable Spring Cloud CircuitBreaker instrumentation.
|
||||
*/
|
||||
private boolean enabled = true;
|
||||
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2018-2019 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
|
||||
*
|
||||
* https://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.circuitbreaker;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Function;
|
||||
|
||||
import brave.Span;
|
||||
import brave.Tracer;
|
||||
|
||||
/**
|
||||
* Trace representation of a {@link Function}.
|
||||
*
|
||||
* @param <T> type returned by the fallback
|
||||
* @since 2.2.1
|
||||
*/
|
||||
public class TraceFunction<T> implements Function<Throwable, T> {
|
||||
|
||||
private final Tracer tracer;
|
||||
|
||||
private final Function<Throwable, T> delegate;
|
||||
|
||||
private final AtomicReference<Span> span;
|
||||
|
||||
public TraceFunction(Tracer tracer, Function<Throwable, T> delegate) {
|
||||
this.tracer = tracer;
|
||||
this.delegate = delegate;
|
||||
this.span = new AtomicReference<>(this.tracer.nextSpan());
|
||||
}
|
||||
|
||||
@Override
|
||||
public T apply(Throwable throwable) {
|
||||
String name = this.delegate.getClass().getSimpleName();
|
||||
Span span = this.span.get().name(name);
|
||||
Throwable tr = null;
|
||||
try (Tracer.SpanInScope ws = this.tracer.withSpanInScope(span.start())) {
|
||||
return this.delegate.apply(throwable);
|
||||
}
|
||||
catch (Throwable t) {
|
||||
tr = t;
|
||||
throw t;
|
||||
}
|
||||
finally {
|
||||
if (tr != null) {
|
||||
String message = tr.getMessage() == null ? tr.getClass().getSimpleName()
|
||||
: tr.getMessage();
|
||||
span.tag("error", message);
|
||||
}
|
||||
span.finish();
|
||||
this.span.set(null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2018-2019 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
|
||||
*
|
||||
* https://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.circuitbreaker;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import brave.Span;
|
||||
import brave.Tracer;
|
||||
|
||||
/**
|
||||
* Trace representation of a {@link Supplier}.
|
||||
*
|
||||
* @param <T> type returned by the supplier
|
||||
* @since 2.2.1
|
||||
*/
|
||||
public class TraceSupplier<T> implements Supplier<T> {
|
||||
|
||||
private final Tracer tracer;
|
||||
|
||||
private final Supplier<T> delegate;
|
||||
|
||||
private final AtomicReference<Span> span;
|
||||
|
||||
public TraceSupplier(Tracer tracer, Supplier<T> delegate) {
|
||||
this.tracer = tracer;
|
||||
this.delegate = delegate;
|
||||
this.span = new AtomicReference<>(this.tracer.nextSpan());
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
String name = this.delegate.getClass().getSimpleName();
|
||||
Span span = this.span.get().name(name);
|
||||
Throwable tr = null;
|
||||
try (Tracer.SpanInScope ws = this.tracer.withSpanInScope(span.start())) {
|
||||
return this.delegate.get();
|
||||
}
|
||||
catch (Throwable t) {
|
||||
tr = t;
|
||||
throw t;
|
||||
}
|
||||
finally {
|
||||
if (tr != null) {
|
||||
String message = tr.getMessage() == null ? tr.getClass().getSimpleName()
|
||||
: tr.getMessage();
|
||||
span.tag("error", message);
|
||||
}
|
||||
span.finish();
|
||||
this.span.set(null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,6 +16,7 @@ org.springframework.cloud.sleuth.instrument.async.AsyncDefaultAutoConfiguration,
|
||||
org.springframework.cloud.sleuth.instrument.scheduling.TraceSchedulingAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.instrument.web.client.feign.TraceFeignClientAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.instrument.hystrix.SleuthHystrixAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.instrument.circuitbreaker.SleuthCircuitBreakerAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.instrument.rxjava.RxJavaAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.instrument.reactor.TraceReactorAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.instrument.web.TraceWebFluxAutoConfiguration,\
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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
|
||||
*
|
||||
* https://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.circuitbreaker;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import brave.ScopedSpan;
|
||||
import brave.Span;
|
||||
import brave.Tracer;
|
||||
import brave.sampler.Sampler;
|
||||
import org.assertj.core.api.BDDAssertions;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JCircuitBreakerFactory;
|
||||
import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
|
||||
import org.springframework.cloud.sleuth.util.ArrayListSpanReporter;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.assertj.core.api.BDDAssertions.then;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = CircuitBreakerIntegrationTests.Config.class)
|
||||
public class CircuitBreakerIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
ArrayListSpanReporter reporter;
|
||||
|
||||
@Autowired
|
||||
Tracer tracer;
|
||||
|
||||
@Autowired
|
||||
CircuitBreakerFactory factory;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.reporter.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_pass_tracing_information_when_using_circuit_breaker() {
|
||||
// given
|
||||
Tracer tracer = this.tracer;
|
||||
ScopedSpan scopedSpan = null;
|
||||
try {
|
||||
scopedSpan = tracer.startScopedSpan("start");
|
||||
// when
|
||||
Span span = this.factory.create("name").run(tracer::currentSpan);
|
||||
|
||||
then(span).isNotNull();
|
||||
then(scopedSpan.context().traceIdString())
|
||||
.isEqualTo(span.context().traceIdString());
|
||||
}
|
||||
finally {
|
||||
scopedSpan.finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_pass_tracing_information_when_using_circuit_breaker_with_fallback() {
|
||||
// given
|
||||
Tracer tracer = this.tracer;
|
||||
AtomicReference<Span> first = new AtomicReference<>();
|
||||
AtomicReference<Span> second = new AtomicReference<>();
|
||||
ScopedSpan scopedSpan = null;
|
||||
try {
|
||||
scopedSpan = tracer.startScopedSpan("start");
|
||||
// when
|
||||
BDDAssertions.thenThrownBy(() -> this.factory.create("name").run(() -> {
|
||||
first.set(tracer.currentSpan());
|
||||
throw new IllegalStateException("boom");
|
||||
}, throwable -> {
|
||||
second.set(tracer.currentSpan());
|
||||
throw new IllegalStateException("boom2");
|
||||
})).isInstanceOf(IllegalStateException.class).hasMessageContaining("boom2");
|
||||
|
||||
then(this.reporter.getSpans()).hasSize(2);
|
||||
then(scopedSpan.context().traceIdString())
|
||||
.isEqualTo(first.get().context().traceIdString());
|
||||
then(scopedSpan.context().traceIdString())
|
||||
.isEqualTo(second.get().context().traceIdString());
|
||||
then(first.get().context().spanIdString())
|
||||
.isNotEqualTo(second.get().context().spanIdString());
|
||||
|
||||
zipkin2.Span reportedSpan = this.reporter.getSpans().get(0);
|
||||
then(reportedSpan.name()).contains("circuitbreakerintegrationtests");
|
||||
then(reportedSpan.tags().get("error")).contains("boom");
|
||||
|
||||
reportedSpan = this.reporter.getSpans().get(1);
|
||||
then(reportedSpan.name()).contains("circuitbreakerintegrationtests");
|
||||
then(reportedSpan.tags().get("error")).contains("boom2");
|
||||
}
|
||||
finally {
|
||||
scopedSpan.finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
static class Config {
|
||||
|
||||
@Bean
|
||||
ArrayListSpanReporter arrayListSpanReporter() {
|
||||
return new ArrayListSpanReporter();
|
||||
}
|
||||
|
||||
@Bean
|
||||
Resilience4JCircuitBreakerFactory resilience4JCircuitBreakerFactory() {
|
||||
return new Resilience4JCircuitBreakerFactory();
|
||||
}
|
||||
|
||||
@Bean
|
||||
Sampler sampler() {
|
||||
return Sampler.ALWAYS_SAMPLE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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
|
||||
*
|
||||
* https://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.circuitbreaker;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import brave.ScopedSpan;
|
||||
import brave.Span;
|
||||
import brave.Tracer;
|
||||
import brave.Tracing;
|
||||
import brave.propagation.StrictScopeDecorator;
|
||||
import brave.propagation.ThreadLocalCurrentTraceContext;
|
||||
import brave.sampler.Sampler;
|
||||
import org.assertj.core.api.BDDAssertions;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JCircuitBreakerFactory;
|
||||
import org.springframework.cloud.sleuth.util.ArrayListSpanReporter;
|
||||
|
||||
import static org.assertj.core.api.BDDAssertions.then;
|
||||
|
||||
public class CircuitBreakerTests {
|
||||
|
||||
ArrayListSpanReporter reporter = new ArrayListSpanReporter();
|
||||
|
||||
Tracing tracing = Tracing.newBuilder()
|
||||
.currentTraceContext(ThreadLocalCurrentTraceContext.newBuilder()
|
||||
.addScopeDecorator(StrictScopeDecorator.create()).build())
|
||||
.spanReporter(this.reporter).sampler(Sampler.ALWAYS_SAMPLE).build();
|
||||
|
||||
Tracer tracer = this.tracing.tracer();
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.reporter.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_pass_tracing_information_when_using_circuit_breaker() {
|
||||
// given
|
||||
Tracer tracer = this.tracer;
|
||||
ScopedSpan scopedSpan = null;
|
||||
try {
|
||||
scopedSpan = tracer.startScopedSpan("start");
|
||||
// when
|
||||
Span span = new Resilience4JCircuitBreakerFactory().create("name")
|
||||
.run(new TraceSupplier<>(tracer, tracer::currentSpan));
|
||||
|
||||
then(span).isNotNull();
|
||||
then(scopedSpan.context().traceIdString())
|
||||
.isEqualTo(span.context().traceIdString());
|
||||
}
|
||||
finally {
|
||||
scopedSpan.finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_pass_tracing_information_when_using_circuit_breaker_with_fallback() {
|
||||
// given
|
||||
Tracer tracer = this.tracer;
|
||||
AtomicReference<Span> first = new AtomicReference<>();
|
||||
AtomicReference<Span> second = new AtomicReference<>();
|
||||
ScopedSpan scopedSpan = null;
|
||||
try {
|
||||
scopedSpan = tracer.startScopedSpan("start");
|
||||
// when
|
||||
BDDAssertions.thenThrownBy(() -> new Resilience4JCircuitBreakerFactory()
|
||||
.create("name").run(new TraceSupplier<>(tracer, () -> {
|
||||
first.set(tracer.currentSpan());
|
||||
throw new IllegalStateException("boom");
|
||||
}), new TraceFunction<>(tracer, throwable -> {
|
||||
second.set(tracer.currentSpan());
|
||||
throw new IllegalStateException("boom2");
|
||||
}))).isInstanceOf(IllegalStateException.class)
|
||||
.hasMessageContaining("boom2");
|
||||
|
||||
then(this.reporter.getSpans()).hasSize(2);
|
||||
then(scopedSpan.context().traceIdString())
|
||||
.isEqualTo(first.get().context().traceIdString());
|
||||
then(scopedSpan.context().traceIdString())
|
||||
.isEqualTo(second.get().context().traceIdString());
|
||||
then(first.get().context().spanIdString())
|
||||
.isNotEqualTo(second.get().context().spanIdString());
|
||||
|
||||
zipkin2.Span reportedSpan = this.reporter.getSpans().get(1);
|
||||
then(reportedSpan.name()).contains("circuitbreakertests");
|
||||
then(reportedSpan.tags().get("error")).contains("boom2");
|
||||
}
|
||||
finally {
|
||||
scopedSpan.finish();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user