Support for Micrometer Observations (#1131)
with this change we're introducing Micrometer Observations for CircuitBreakers
This commit is contained in:
committed by
GitHub
parent
c7790815fb
commit
17311ebfd7
58
docs/pom.xml
58
docs/pom.xml
@@ -20,6 +20,12 @@
|
||||
<upload-docs-zip.phase>deploy</upload-docs-zip.phase>
|
||||
<!-- Don't upload docs jar to central / repo.spring.io -->
|
||||
<maven-deploy-plugin-default.phase>none</maven-deploy-plugin-default.phase>
|
||||
|
||||
<!-- Observability -->
|
||||
<micrometer-docs-generator.version>1.0.0-M5</micrometer-docs-generator.version>
|
||||
<micrometer-docs-generator.inputPath>${maven.multiModuleProjectDirectory}/spring-cloud-commons/</micrometer-docs-generator.inputPath>
|
||||
<micrometer-docs-generator.inclusionPattern>.*</micrometer-docs-generator.inclusionPattern>
|
||||
<micrometer-docs-generator.outputPath>${maven.multiModuleProjectDirectory}/target/</micrometer-docs-generator.outputPath>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@@ -46,6 +52,58 @@
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>generate-metrics-metadata</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>java</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<mainClass>io.micrometer.docs.metrics.DocsFromSources</mainClass>
|
||||
<includePluginDependencies>true</includePluginDependencies>
|
||||
<arguments>
|
||||
<argument>${micrometer-docs-generator.inputPath}</argument>
|
||||
<argument>${micrometer-docs-generator.inclusionPattern}</argument>
|
||||
<argument>${micrometer-docs-generator.outputPath}</argument>
|
||||
</arguments>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>generate-tracing-metadata</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>java</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<mainClass>io.micrometer.docs.spans.DocsFromSources</mainClass>
|
||||
<includePluginDependencies>true</includePluginDependencies>
|
||||
<arguments>
|
||||
<argument>${micrometer-docs-generator.inputPath}</argument>
|
||||
<argument>${micrometer-docs-generator.inclusionPattern}</argument>
|
||||
<argument>${micrometer-docs-generator.outputPath}</argument>
|
||||
</arguments>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.micrometer
|
||||
</groupId>
|
||||
<artifactId>micrometer-docs-generator-spans</artifactId>
|
||||
<version>${micrometer-docs-generator.version}
|
||||
</version>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micrometer
|
||||
</groupId>
|
||||
<artifactId>micrometer-docs-generator-metrics</artifactId>
|
||||
<version>${micrometer-docs-generator.version}
|
||||
</version>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
|
||||
8
docs/src/main/asciidoc/_observability.adoc
Normal file
8
docs/src/main/asciidoc/_observability.adoc
Normal file
@@ -0,0 +1,8 @@
|
||||
:root-target: ../../../target/
|
||||
|
||||
[[observability]]
|
||||
== Observability metadata
|
||||
|
||||
include::{root-target}_metrics.adoc[]
|
||||
|
||||
include::{root-target}_spans.adoc[]
|
||||
@@ -11,4 +11,6 @@ This appendix provides a list of common {project-full-name} properties and refer
|
||||
NOTE: Property contributions can come from additional jar files on your classpath, so you should not consider this an exhaustive list.
|
||||
Also, you can define your own properties.
|
||||
|
||||
include::_configprops.adoc[]
|
||||
include::_configprops.adoc[]
|
||||
|
||||
include::_observability.adoc[]
|
||||
|
||||
@@ -192,5 +192,10 @@
|
||||
<artifactId>reactor-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micrometer</groupId>
|
||||
<artifactId>micrometer-observation-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2013-2021 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.client.circuitbreaker.observation;
|
||||
|
||||
import io.micrometer.common.docs.KeyName;
|
||||
import io.micrometer.observation.Observation;
|
||||
import io.micrometer.observation.docs.DocumentedObservation;
|
||||
|
||||
enum CircuitBreakerDocumentedObservation implements DocumentedObservation {
|
||||
|
||||
/**
|
||||
* Observation created when we wrap a Supplier passed to the CircuitBreaker.
|
||||
*/
|
||||
CIRCUIT_BREAKER_SUPPLIER_OBSERVATION {
|
||||
@Override
|
||||
public Class<? extends Observation.ObservationConvention<? extends Observation.Context>> getDefaultConvention() {
|
||||
return DefaultCircuitBreakerObservationConvention.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyName[] getLowCardinalityKeyNames() {
|
||||
return LowCardinalityTags.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefix() {
|
||||
return "spring.cloud.circuitbreaker";
|
||||
}
|
||||
|
||||
// TODO: Move this to convention with the next micrometer release
|
||||
// @Override
|
||||
// public String getContextualName() {
|
||||
// return "circuit-breaker";
|
||||
// }
|
||||
},
|
||||
|
||||
/**
|
||||
* Observation created when we wrap a Function passed to the CircuitBreaker as
|
||||
* fallback.
|
||||
*/
|
||||
CIRCUIT_BREAKER_FUNCTION_OBSERVATION {
|
||||
@Override
|
||||
public Class<? extends Observation.ObservationConvention<? extends Observation.Context>> getDefaultConvention() {
|
||||
return DefaultCircuitBreakerObservationConvention.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyName[] getLowCardinalityKeyNames() {
|
||||
return LowCardinalityTags.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefix() {
|
||||
return "spring.cloud.circuitbreaker";
|
||||
}
|
||||
|
||||
// TODO: Move this to convention with the next micrometer release
|
||||
// @Override
|
||||
// public String getContextualName() {
|
||||
// return "circuit-breaker fallback";
|
||||
// }
|
||||
};
|
||||
|
||||
enum LowCardinalityTags implements KeyName {
|
||||
|
||||
/**
|
||||
* Defines the type of wrapped lambda.
|
||||
*/
|
||||
OBJECT_TYPE {
|
||||
@Override
|
||||
public String getKeyName() {
|
||||
return "spring.cloud.circuitbreaker.type";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2018-2021 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.client.circuitbreaker.observation;
|
||||
|
||||
import io.micrometer.observation.Observation;
|
||||
|
||||
/**
|
||||
* Circuit Breaker {@link Observation.Context}.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public class CircuitBreakerObservationContext extends Observation.Context {
|
||||
|
||||
private final Type type;
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link CircuitBreakerDocumentedObservation}.
|
||||
* @param type type of wrapped object
|
||||
*/
|
||||
public CircuitBreakerObservationContext(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the wrapped object type.
|
||||
* @return type of wrapped object
|
||||
*/
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes the type of wrapped object.
|
||||
*/
|
||||
public enum Type {
|
||||
|
||||
/**
|
||||
* Fallback function.
|
||||
*/
|
||||
FUNCTION,
|
||||
|
||||
/**
|
||||
* Operation to run.
|
||||
*/
|
||||
SUPPLIER
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2018-2021 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.client.circuitbreaker.observation;
|
||||
|
||||
import io.micrometer.observation.Observation;
|
||||
|
||||
/**
|
||||
* {@link Observation.ObservationConvention} for {@link CircuitBreakerObservationContext}.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public interface CircuitBreakerObservationConvention
|
||||
extends Observation.ObservationConvention<CircuitBreakerObservationContext> {
|
||||
|
||||
@Override
|
||||
default boolean supportsContext(Observation.Context context) {
|
||||
return context instanceof CircuitBreakerObservationContext;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2018-2021 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.client.circuitbreaker.observation;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import io.micrometer.common.KeyValues;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link CircuitBreakerObservationContext}.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public class DefaultCircuitBreakerObservationConvention implements CircuitBreakerObservationConvention {
|
||||
|
||||
static final DefaultCircuitBreakerObservationConvention INSTANCE = new DefaultCircuitBreakerObservationConvention();
|
||||
|
||||
@Override
|
||||
public KeyValues getLowCardinalityKeyValues(CircuitBreakerObservationContext context) {
|
||||
return KeyValues.of(CircuitBreakerDocumentedObservation.LowCardinalityTags.OBJECT_TYPE
|
||||
.of(context.getType().name().toLowerCase(Locale.ROOT)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "spring.cloud.circuitbreaker";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2018-2021 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.client.circuitbreaker.observation;
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
|
||||
import org.springframework.cloud.client.circuitbreaker.CircuitBreaker;
|
||||
|
||||
/**
|
||||
* Observed Circuit Breaker.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public class ObservedCircuitBreaker implements CircuitBreaker {
|
||||
|
||||
private final CircuitBreaker delegate;
|
||||
|
||||
private final ObservationRegistry observationRegistry;
|
||||
|
||||
private CircuitBreakerObservationConvention customConvention;
|
||||
|
||||
public ObservedCircuitBreaker(CircuitBreaker delegate, ObservationRegistry observationRegistry) {
|
||||
this.delegate = delegate;
|
||||
this.observationRegistry = observationRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T run(Supplier<T> toRun, Function<Throwable, T> fallback) {
|
||||
return this.delegate.run(
|
||||
new ObservedSupplier<>(this.customConvention,
|
||||
new CircuitBreakerObservationContext(CircuitBreakerObservationContext.Type.SUPPLIER),
|
||||
"circuit-breaker", this.observationRegistry, toRun),
|
||||
new ObservedFunction<>(this.customConvention,
|
||||
new CircuitBreakerObservationContext(CircuitBreakerObservationContext.Type.FUNCTION),
|
||||
"circuit-breaker fallback", this.observationRegistry, fallback));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T run(Supplier<T> toRun) {
|
||||
return this.delegate.run(new ObservedSupplier<>(this.customConvention,
|
||||
new CircuitBreakerObservationContext(CircuitBreakerObservationContext.Type.SUPPLIER), "circuit-breaker",
|
||||
this.observationRegistry, toRun));
|
||||
}
|
||||
|
||||
public void setCustomConvention(CircuitBreakerObservationConvention customConvention) {
|
||||
this.customConvention = customConvention;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2018-2021 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.client.circuitbreaker.observation;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import io.micrometer.observation.Observation;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
|
||||
/**
|
||||
* Observed {@link Function}.
|
||||
*
|
||||
* @param <T> type returned by the fallback
|
||||
* @since 4.0.0
|
||||
*/
|
||||
class ObservedFunction<T> implements Function<Throwable, T> {
|
||||
|
||||
private final Function<Throwable, T> delegate;
|
||||
|
||||
private final Observation observation;
|
||||
|
||||
// TODO: Move out contextual name with the next micrometer release
|
||||
ObservedFunction(CircuitBreakerObservationConvention customConvention, CircuitBreakerObservationContext context,
|
||||
String conextualName, ObservationRegistry observationRegistry, Function<Throwable, T> toRun) {
|
||||
this.delegate = toRun;
|
||||
this.observation = CircuitBreakerDocumentedObservation.CIRCUIT_BREAKER_SUPPLIER_OBSERVATION.observation(
|
||||
customConvention, DefaultCircuitBreakerObservationConvention.INSTANCE, context, observationRegistry);
|
||||
this.observation.contextualName(conextualName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T apply(Throwable throwable) {
|
||||
return this.observation.observe(() -> this.delegate.apply(throwable));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2018-2021 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.client.circuitbreaker.observation;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import io.micrometer.observation.Observation;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
|
||||
/**
|
||||
* Observed {@link Supplier}.
|
||||
*
|
||||
* @param <T> type returned by the supplier
|
||||
* @since 4.0.0
|
||||
*/
|
||||
class ObservedSupplier<T> implements Supplier<T> {
|
||||
|
||||
private final Supplier<T> delegate;
|
||||
|
||||
private final Observation observation;
|
||||
|
||||
// TODO: Move out contextual name with the next micrometer release
|
||||
ObservedSupplier(CircuitBreakerObservationConvention customConvention, CircuitBreakerObservationContext context,
|
||||
String contextualName, ObservationRegistry observationRegistry, Supplier<T> toRun) {
|
||||
this.delegate = toRun;
|
||||
this.observation = CircuitBreakerDocumentedObservation.CIRCUIT_BREAKER_SUPPLIER_OBSERVATION.observation(
|
||||
customConvention, DefaultCircuitBreakerObservationConvention.INSTANCE, context, observationRegistry);
|
||||
this.observation.contextualName(contextualName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
return this.observation.observe(this.delegate);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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.client.circuitbreaker.observation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import io.micrometer.common.KeyValues;
|
||||
import io.micrometer.observation.Observation;
|
||||
import io.micrometer.observation.ObservationHandler;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import io.micrometer.observation.tck.ObservationContextAssert;
|
||||
import io.micrometer.observation.tck.TestObservationRegistry;
|
||||
import io.micrometer.observation.tck.TestObservationRegistryAssert;
|
||||
import org.assertj.core.api.BDDAssertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.cloud.client.circuitbreaker.CircuitBreaker;
|
||||
|
||||
import static org.assertj.core.api.BDDAssertions.then;
|
||||
|
||||
class ObservedCircuitBreakerTests {
|
||||
|
||||
TestObservationRegistry registry = TestObservationRegistry.create();
|
||||
|
||||
@Test
|
||||
void should_wrap_circuit_breaker_in_observation() {
|
||||
CircuitBreaker delegate = new CircuitBreaker() {
|
||||
@Override
|
||||
public <T> T run(Supplier<T> toRun, Function<Throwable, T> fallback) {
|
||||
return toRun.get();
|
||||
}
|
||||
};
|
||||
ObservedCircuitBreaker circuitBreaker = new ObservedCircuitBreaker(delegate, registry);
|
||||
|
||||
String result = circuitBreaker.run(() -> "hello");
|
||||
|
||||
then(result).isEqualTo("hello");
|
||||
TestObservationRegistryAssert.assertThat(registry).hasSingleObservationThat()
|
||||
.hasNameEqualTo("spring.cloud.circuitbreaker")
|
||||
.hasLowCardinalityKeyValue("spring.cloud.circuitbreaker.type", "supplier")
|
||||
.hasContextualNameEqualTo("circuit-breaker");
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_wrap_circuit_breaker_in_observation_with_custom_convention() {
|
||||
CircuitBreaker delegate = new CircuitBreaker() {
|
||||
@Override
|
||||
public <T> T run(Supplier<T> toRun, Function<Throwable, T> fallback) {
|
||||
return toRun.get();
|
||||
}
|
||||
};
|
||||
ObservedCircuitBreaker circuitBreaker = new ObservedCircuitBreaker(delegate, registry);
|
||||
circuitBreaker.setCustomConvention(new CircuitBreakerObservationConvention() {
|
||||
|
||||
@Override
|
||||
public KeyValues getLowCardinalityKeyValues(CircuitBreakerObservationContext context) {
|
||||
return KeyValues.of("bar", "baz");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "foo";
|
||||
}
|
||||
});
|
||||
|
||||
String result = circuitBreaker.run(() -> "hello");
|
||||
|
||||
then(result).isEqualTo("hello");
|
||||
TestObservationRegistryAssert.assertThat(registry).hasSingleObservationThat().hasNameEqualTo("foo")
|
||||
.hasLowCardinalityKeyValue("bar", "baz").hasContextualNameEqualTo("circuit-breaker");
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_wrap_circuit_breaker_with_fallback_in_observation() {
|
||||
ObservationRegistry registry = ObservationRegistry.create();
|
||||
MyHandler myHandler = new MyHandler();
|
||||
registry.observationConfig().observationHandler(myHandler);
|
||||
CircuitBreaker delegate = new CircuitBreaker() {
|
||||
@Override
|
||||
public <T> T run(Supplier<T> toRun, Function<Throwable, T> fallback) {
|
||||
try {
|
||||
return toRun.get();
|
||||
}
|
||||
catch (Throwable t) {
|
||||
return fallback.apply(t);
|
||||
}
|
||||
}
|
||||
};
|
||||
ObservedCircuitBreaker circuitBreaker = new ObservedCircuitBreaker(delegate, registry);
|
||||
|
||||
String result = circuitBreaker.run(() -> {
|
||||
throw new IllegalStateException("BOOM!");
|
||||
}, throwable -> "goodbye");
|
||||
|
||||
then(result).isEqualTo("goodbye");
|
||||
List<Observation.Context> contexts = myHandler.contexts;
|
||||
|
||||
// TODO: Convert to usage of test registry assert with the next micrometer release
|
||||
BDDAssertions.then(contexts).hasSize(2);
|
||||
BDDAssertions.then(contexts.get(0))
|
||||
.satisfies(context -> ObservationContextAssert.then(context)
|
||||
.hasNameEqualTo("spring.cloud.circuitbreaker").hasContextualNameEqualTo("circuit-breaker")
|
||||
.hasLowCardinalityKeyValue("spring.cloud.circuitbreaker.type", "supplier"));
|
||||
BDDAssertions.then(contexts.get(1)).satisfies(context -> ObservationContextAssert.then(context)
|
||||
.hasNameEqualTo("spring.cloud.circuitbreaker").hasContextualNameEqualTo("circuit-breaker fallback")
|
||||
.hasLowCardinalityKeyValue("spring.cloud.circuitbreaker.type", "function"));
|
||||
}
|
||||
|
||||
// TODO: Convert to usage of test registry assert with the next micrometer release
|
||||
static class MyHandler implements ObservationHandler<Observation.Context> {
|
||||
|
||||
List<Observation.Context> contexts = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void onStop(Observation.Context context) {
|
||||
this.contexts.add(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsContext(Observation.Context context) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user