diff --git a/docs/pom.xml b/docs/pom.xml
index 34de7cc6..b9be0e51 100644
--- a/docs/pom.xml
+++ b/docs/pom.xml
@@ -20,6 +20,12 @@
deploy
none
+
+
+ 1.0.0-M5
+ ${maven.multiModuleProjectDirectory}/spring-cloud-commons/
+ .*
+ ${maven.multiModuleProjectDirectory}/target/
@@ -46,6 +52,58 @@
org.codehaus.mojo
exec-maven-plugin
+
+
+ generate-metrics-metadata
+ prepare-package
+
+ java
+
+
+ io.micrometer.docs.metrics.DocsFromSources
+ true
+
+ ${micrometer-docs-generator.inputPath}
+ ${micrometer-docs-generator.inclusionPattern}
+ ${micrometer-docs-generator.outputPath}
+
+
+
+
+ generate-tracing-metadata
+ prepare-package
+
+ java
+
+
+ io.micrometer.docs.spans.DocsFromSources
+ true
+
+ ${micrometer-docs-generator.inputPath}
+ ${micrometer-docs-generator.inclusionPattern}
+ ${micrometer-docs-generator.outputPath}
+
+
+
+
+
+
+ io.micrometer
+
+ micrometer-docs-generator-spans
+ ${micrometer-docs-generator.version}
+
+ jar
+
+
+ io.micrometer
+
+ micrometer-docs-generator-metrics
+ ${micrometer-docs-generator.version}
+
+ jar
+
+
org.apache.maven.plugins
diff --git a/docs/src/main/asciidoc/_observability.adoc b/docs/src/main/asciidoc/_observability.adoc
new file mode 100644
index 00000000..01121b26
--- /dev/null
+++ b/docs/src/main/asciidoc/_observability.adoc
@@ -0,0 +1,8 @@
+:root-target: ../../../target/
+
+[[observability]]
+== Observability metadata
+
+include::{root-target}_metrics.adoc[]
+
+include::{root-target}_spans.adoc[]
diff --git a/docs/src/main/asciidoc/appendix.adoc b/docs/src/main/asciidoc/appendix.adoc
index 2c18b865..aa8ab264 100644
--- a/docs/src/main/asciidoc/appendix.adoc
+++ b/docs/src/main/asciidoc/appendix.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[]
\ No newline at end of file
+include::_configprops.adoc[]
+
+include::_observability.adoc[]
diff --git a/spring-cloud-commons/pom.xml b/spring-cloud-commons/pom.xml
index 9c92ac82..e96e548d 100644
--- a/spring-cloud-commons/pom.xml
+++ b/spring-cloud-commons/pom.xml
@@ -192,5 +192,10 @@
reactor-test
test
+
+ io.micrometer
+ micrometer-observation-test
+ test
+
diff --git a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/circuitbreaker/observation/CircuitBreakerDocumentedObservation.java b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/circuitbreaker/observation/CircuitBreakerDocumentedObservation.java
new file mode 100644
index 00000000..78ee446e
--- /dev/null
+++ b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/circuitbreaker/observation/CircuitBreakerDocumentedObservation.java
@@ -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";
+ }
+ }
+
+ }
+
+}
diff --git a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/circuitbreaker/observation/CircuitBreakerObservationContext.java b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/circuitbreaker/observation/CircuitBreakerObservationContext.java
new file mode 100644
index 00000000..12ecd8c2
--- /dev/null
+++ b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/circuitbreaker/observation/CircuitBreakerObservationContext.java
@@ -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
+
+ }
+
+}
diff --git a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/circuitbreaker/observation/CircuitBreakerObservationConvention.java b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/circuitbreaker/observation/CircuitBreakerObservationConvention.java
new file mode 100644
index 00000000..21b08250
--- /dev/null
+++ b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/circuitbreaker/observation/CircuitBreakerObservationConvention.java
@@ -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 {
+
+ @Override
+ default boolean supportsContext(Observation.Context context) {
+ return context instanceof CircuitBreakerObservationContext;
+ }
+
+}
diff --git a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/circuitbreaker/observation/DefaultCircuitBreakerObservationConvention.java b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/circuitbreaker/observation/DefaultCircuitBreakerObservationConvention.java
new file mode 100644
index 00000000..f8e41611
--- /dev/null
+++ b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/circuitbreaker/observation/DefaultCircuitBreakerObservationConvention.java
@@ -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";
+ }
+
+}
diff --git a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/circuitbreaker/observation/ObservedCircuitBreaker.java b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/circuitbreaker/observation/ObservedCircuitBreaker.java
new file mode 100644
index 00000000..b30ffe5b
--- /dev/null
+++ b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/circuitbreaker/observation/ObservedCircuitBreaker.java
@@ -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 run(Supplier toRun, Function 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 run(Supplier 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;
+ }
+
+}
diff --git a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/circuitbreaker/observation/ObservedFunction.java b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/circuitbreaker/observation/ObservedFunction.java
new file mode 100644
index 00000000..ca2ea09a
--- /dev/null
+++ b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/circuitbreaker/observation/ObservedFunction.java
@@ -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 type returned by the fallback
+ * @since 4.0.0
+ */
+class ObservedFunction implements Function {
+
+ private final Function 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 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));
+ }
+
+}
diff --git a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/circuitbreaker/observation/ObservedSupplier.java b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/circuitbreaker/observation/ObservedSupplier.java
new file mode 100644
index 00000000..016d6e0d
--- /dev/null
+++ b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/circuitbreaker/observation/ObservedSupplier.java
@@ -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 type returned by the supplier
+ * @since 4.0.0
+ */
+class ObservedSupplier implements Supplier {
+
+ private final Supplier 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 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);
+ }
+
+}
diff --git a/spring-cloud-commons/src/test/java/org/springframework/cloud/client/circuitbreaker/observation/ObservedCircuitBreakerTests.java b/spring-cloud-commons/src/test/java/org/springframework/cloud/client/circuitbreaker/observation/ObservedCircuitBreakerTests.java
new file mode 100644
index 00000000..c674f0fb
--- /dev/null
+++ b/spring-cloud-commons/src/test/java/org/springframework/cloud/client/circuitbreaker/observation/ObservedCircuitBreakerTests.java
@@ -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 run(Supplier toRun, Function 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 run(Supplier toRun, Function 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 run(Supplier toRun, Function 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 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 {
+
+ List contexts = new ArrayList<>();
+
+ @Override
+ public void onStop(Observation.Context context) {
+ this.contexts.add(context);
+ }
+
+ @Override
+ public boolean supportsContext(Observation.Context context) {
+ return true;
+ }
+
+ }
+
+}