From 7c81df37bb4f739c5d6eb41ce44dc29f8c4de145 Mon Sep 17 00:00:00 2001 From: Jonatan Ivanov Date: Fri, 18 Nov 2022 20:10:49 -0800 Subject: [PATCH 1/2] Micrometer Observation API Support --- docs/src/main/asciidoc/_configprops.adoc | 4 +- .../main/asciidoc/spring-cloud-openfeign.adoc | 54 ++++++---- ...eignClientMicrometerEnabledCondition.java} | 8 +- .../openfeign/FeignClientProperties.java | 21 ++-- .../openfeign/FeignClientsConfiguration.java | 24 +++-- ...itional-spring-configuration-metadata.json | 4 +- .../FeignClientConfigurationTests.java | 8 +- ...lientDisabledClientLevelFeaturesTests.java | 10 +- .../FeignClientDisabledFeaturesTests.java | 2 +- ...lientMicrometerEnabledConditionTests.java} | 32 +++--- .../FeignClientOverrideDefaultsTests.java | 101 ++++++++++++++---- .../FeignClientUsingConfigurerTest.java | 8 +- .../FeignClientUsingPropertiesTests.java | 4 +- .../cloud/openfeign/GzipDecodingTests.java | 2 +- ...ts.java => MicrometerPropertiesTests.java} | 16 +-- .../src/test/resources/application.yml | 8 +- 16 files changed, 196 insertions(+), 110 deletions(-) rename spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/{FeignClientMetricsEnabledCondition.java => FeignClientMicrometerEnabledCondition.java} (85%) rename spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/{FeignClientMetricsEnabledConditionTests.java => FeignClientMicrometerEnabledConditionTests.java} (88%) rename spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/{MetricsPropertiesTests.java => MicrometerPropertiesTests.java} (76%) diff --git a/docs/src/main/asciidoc/_configprops.adoc b/docs/src/main/asciidoc/_configprops.adoc index 711773334..6d8de12a4 100644 --- a/docs/src/main/asciidoc/_configprops.adoc +++ b/docs/src/main/asciidoc/_configprops.adoc @@ -29,9 +29,9 @@ |spring.cloud.openfeign.httpclient.ok-http.read-timeout | `60s` | {@link OkHttpClient} read timeout; defaults to 60 seconds. |spring.cloud.openfeign.httpclient.time-to-live | `900` | |spring.cloud.openfeign.httpclient.time-to-live-unit | | -|spring.cloud.openfeign.metrics.enabled | `true` | Enables metrics capability for Feign. +|spring.cloud.openfeign.micrometer.enabled | `true` | Enables Micrometer capabilities for Feign. |spring.cloud.openfeign.oauth2.enabled | `false` | Enables feign interceptor for managing oauth2 access token. |spring.cloud.openfeign.oauth2.load-balanced | `false` | Enables load balancing for oauth2 access token provider. |spring.cloud.openfeign.okhttp.enabled | `false` | Enables the use of the OK HTTP Client by Feign. -|=== \ No newline at end of file +|=== diff --git a/docs/src/main/asciidoc/spring-cloud-openfeign.adoc b/docs/src/main/asciidoc/spring-cloud-openfeign.adoc index 6d473cd92..a1e7ac4ba 100644 --- a/docs/src/main/asciidoc/spring-cloud-openfeign.adoc +++ b/docs/src/main/asciidoc/spring-cloud-openfeign.adoc @@ -121,7 +121,8 @@ Spring Cloud OpenFeign provides the following beans by default for feign (`BeanT * `Decoder` feignDecoder: `ResponseEntityDecoder` (which wraps a `SpringDecoder`) * `Encoder` feignEncoder: `SpringEncoder` * `Logger` feignLogger: `Slf4jLogger` -* `MicrometerCapability` micrometerCapability: If `feign-micrometer` is on the classpath and `MeterRegistry` is available +* `MicrometerObservationCapability` micrometerObservationCapability: If `feign-micrometer` is on the classpath and `ObservationRegistry` is available +* `MicrometerCapability` micrometerCapability: If `feign-micrometer` is on the classpath, `MeterRegistry` is available and `ObservationRegistry` is not available * `CachingCapability` cachingCapability: If `@EnableCaching` annotation is used. Can be disabled via `spring.cloud.openfeign.cache.enabled`. * `Contract` feignContract: `SpringMvcContract` * `Feign.Builder` feignBuilder: `FeignCircuitBreaker.Builder` @@ -146,7 +147,7 @@ Spring Cloud OpenFeign _does not_ provide the following beans by default for fei * `Collection` * `SetterFactory` * `QueryMapEncoder` -* `Capability` (`MicrometerCapability` and `CachingCapability` are provided by default) +* `Capability` (`MicrometerObservationCapability` and `CachingCapability` are provided by default) A bean of `Retryer.NEVER_RETRY` with the type `Retryer` is created by default, which will disable retrying. Notice this retrying behavior is different from the Feign default one, where it will automatically retry IOExceptions, @@ -204,7 +205,7 @@ spring: - com.example.FooCapability - com.example.BarCapability queryMapEncoder: com.example.SimpleQueryMapEncoder - metrics.enabled: false + micrometer.enabled: false ---- Default configurations can be specified in the `@EnableFeignClients` attribute `defaultConfiguration` in a similar manner as described above. The difference is that this configuration will apply to _all_ feign clients. @@ -311,12 +312,12 @@ class FooController { private FooClient adminClient; @Autowired - public FooController(Client client, Encoder encoder, Decoder decoder, Contract contract, MicrometerCapability micrometerCapability) { + public FooController(Client client, Encoder encoder, Decoder decoder, Contract contract, MicrometerObservationCapability micrometerObservationCapability) { this.fooClient = Feign.builder().client(client) .encoder(encoder) .decoder(decoder) .contract(contract) - .addCapability(micrometerCapability) + .addCapability(micrometerObservationCapability) .requestInterceptor(new BasicAuthRequestInterceptor("user", "user")) .target(FooClient.class, "https://PROD-SVC"); @@ -324,7 +325,7 @@ class FooController { .encoder(encoder) .decoder(decoder) .contract(contract) - .addCapability(micrometerCapability) + .addCapability(micrometerObservationCapability) .requestInterceptor(new BasicAuthRequestInterceptor("admin", "admin")) .target(FooClient.class, "https://PROD-SVC"); } @@ -602,7 +603,7 @@ public class FooConfiguration { === Feign Capability support The Feign capabilities expose core Feign components so that these components can be modified. For example, the capabilities can take the `Client`, _decorate_ it, and give the decorated instance back to Feign. -The support for metrics libraries is a good real-life example for this. See <>. +The support for Micrometer is a good real-life example for this. See <>. Creating one or more `Capability` beans and placing them in a `@FeignClient` configuration lets you register them and modify the behavior of the involved client. @@ -617,29 +618,42 @@ public class FooConfiguration { } ---- -=== Feign metrics +=== Micrometer Support -If all of the following conditions are true, a `MicrometerCapability` bean is created and registered so that your Feign client publishes metrics to Micrometer: +If all of the following conditions are true, a `MicrometerObservationCapability` bean is created and registered so that your Feign client is observable by Micrometer: * `feign-micrometer` is on the classpath -* A `MeterRegistry` bean is available -* feign metrics properties are set to `true` (by default) - - `spring.cloud.openfeign.metrics.enabled=true` (for all clients) - - `spring.cloud.openfeign.client.config.feignName.metrics.enabled=true` (for a single client) +* A `ObservationRegistry` bean is available +* feign micrometer properties are set to `true` (by default) + - `spring.cloud.openfeign.micrometer.enabled=true` (for all clients) + - `spring.cloud.openfeign.client.config.feignName.micrometer.enabled=true` (for a single client) -NOTE: If your application already uses Micrometer, enabling metrics is as simple as putting `feign-micrometer` onto your classpath. +NOTE: If your application already uses Micrometer, enabling this feature is as simple as putting `feign-micrometer` onto your classpath. You can also disable the feature by either: * excluding `feign-micrometer` from your classpath -* setting one of the feign metrics properties to `false` - - `spring.cloud.openfeign.metrics.enabled=false` - - `spring.cloud.openfeign.client.config.feignName.metrics.enabled=false` +* setting one of the feign micrometer properties to `false` + - `spring.cloud.openfeign.micrometer.enabled=false` + - `spring.cloud.openfeign.client.config.feignName.micrometer.enabled=false` -NOTE: `spring.cloud.openfeign.metrics.enabled=false` disables metrics support for *all* Feign clients regardless of the value of the client-level flags: `spring.cloud.openfeign.client.config.feignName.metrics.enabled`. -If you want to enable or disable merics per client, don't set `spring.cloud.openfeign.metrics.enabled` and use `spring.cloud.openfeign.client.config.feignName.metrics.enabled`. +NOTE: `spring.cloud.openfeign.micrometer.enabled=false` disables Micrometer support for *all* Feign clients regardless of the value of the client-level flags: `spring.cloud.openfeign.client.config.feignName.micrometer.enabled`. +If you want to enable or disable Micrometer support per client, don't set `spring.cloud.openfeign.micrometer.enabled` and use `spring.cloud.openfeign.client.config.feignName.micrometer.enabled`. -You can also customize the `MicrometerCapability` by registering your own bean: +You can also customize the `MicrometerObservationCapability` by registering your own bean: + +[source,java,indent=0] +---- +@Configuration +public class FooConfiguration { + @Bean + public MicrometerObservationCapability micrometerObservationCapability(ObservationRegistry registry) { + return new MicrometerObservationCapability(registry); + } +} +---- + +It is still possible to use `MicrometerCapability` with Feign (metrics-only support), you need to disable Micrometer support (`spring.cloud.openfeign.micrometer.enabled=false`) and create a `MicrometerCapability` bean: [source,java,indent=0] ---- diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientMetricsEnabledCondition.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientMicrometerEnabledCondition.java similarity index 85% rename from spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientMetricsEnabledCondition.java rename to spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientMicrometerEnabledCondition.java index d76a8ac68..bef662ca2 100644 --- a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientMetricsEnabledCondition.java +++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientMicrometerEnabledCondition.java @@ -25,7 +25,7 @@ /** * @author Jonatan Ivanov */ -class FeignClientMetricsEnabledCondition implements Condition { +class FeignClientMicrometerEnabledCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { @@ -38,9 +38,9 @@ public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) FeignClientProperties.FeignClientConfiguration feignClientConfig = feignClientConfigMap .get(context.getEnvironment().getProperty("spring.cloud.openfeign.client.name")); if (feignClientConfig != null) { - FeignClientProperties.MetricsProperties metrics = feignClientConfig.getMetrics(); - if (metrics != null && metrics.getEnabled() != null) { - return metrics.getEnabled(); + FeignClientProperties.MicrometerProperties micrometer = feignClientConfig.getMicrometer(); + if (micrometer != null && micrometer.getEnabled() != null) { + return micrometer.getEnabled(); } } } diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientProperties.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientProperties.java index 16ae326b6..134e4891f 100644 --- a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientProperties.java +++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientProperties.java @@ -144,7 +144,7 @@ public static class FeignClientConfiguration { private Class queryMapEncoder; - private MetricsProperties metrics; + private MicrometerProperties micrometer; private Boolean followRedirects; @@ -274,12 +274,12 @@ public void setQueryMapEncoder(Class queryMapEncoder) { this.queryMapEncoder = queryMapEncoder; } - public MetricsProperties getMetrics() { - return metrics; + public MicrometerProperties getMicrometer() { + return micrometer; } - public void setMetrics(MetricsProperties metrics) { - this.metrics = metrics; + public void setMicrometer(MicrometerProperties micrometer) { + this.micrometer = micrometer; } public Boolean isFollowRedirects() { @@ -317,7 +317,8 @@ public boolean equals(Object o) { && Objects.equals(defaultRequestHeaders, that.defaultRequestHeaders) && Objects.equals(defaultQueryParameters, that.defaultQueryParameters) && Objects.equals(capabilities, that.capabilities) - && Objects.equals(queryMapEncoder, that.queryMapEncoder) && Objects.equals(metrics, that.metrics) + && Objects.equals(queryMapEncoder, that.queryMapEncoder) + && Objects.equals(micrometer, that.micrometer) && Objects.equals(followRedirects, that.followRedirects) && Objects.equals(url, that.url); } @@ -325,15 +326,15 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(loggerLevel, connectTimeout, readTimeout, retryer, errorDecoder, requestInterceptors, dismiss404, encoder, decoder, contract, exceptionPropagationPolicy, defaultQueryParameters, - defaultRequestHeaders, capabilities, queryMapEncoder, metrics, followRedirects, url); + defaultRequestHeaders, capabilities, queryMapEncoder, micrometer, followRedirects, url); } } /** - * Metrics configuration for Feign Client. + * Micrometer configuration for Feign Client. */ - public static class MetricsProperties { + public static class MicrometerProperties { private Boolean enabled = true; @@ -354,7 +355,7 @@ public boolean equals(Object o) { return false; } - MetricsProperties that = (MetricsProperties) o; + MicrometerProperties that = (MicrometerProperties) o; return Objects.equals(enabled, that.enabled); } diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientsConfiguration.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientsConfiguration.java index 6dfebdfbf..aa9dd2ac8 100644 --- a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientsConfiguration.java +++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientsConfiguration.java @@ -29,8 +29,10 @@ import feign.form.MultipartFormContentProcessor; import feign.form.spring.SpringFormEncoder; import feign.micrometer.MicrometerCapability; +import feign.micrometer.MicrometerObservationCapability; import feign.optionals.OptionalDecoder; import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.observation.ObservationRegistry; import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.ObjectProvider; @@ -235,16 +237,24 @@ public Feign.Builder circuitBreakerFeignBuilder() { } @Configuration(proxyBeanMethods = false) - @ConditionalOnBean(type = "io.micrometer.core.instrument.MeterRegistry") - @ConditionalOnClass(name = "feign.micrometer.MicrometerCapability") - @ConditionalOnProperty(name = "spring.cloud.openfeign.metrics.enabled", matchIfMissing = true) - @Conditional(FeignClientMetricsEnabledCondition.class) - protected static class MetricsConfiguration { + @ConditionalOnProperty(name = "spring.cloud.openfeign.micrometer.enabled", matchIfMissing = true) + @Conditional(FeignClientMicrometerEnabledCondition.class) + protected static class MicrometerConfiguration { @Bean @ConditionalOnMissingBean - public MicrometerCapability micrometerCapability(MeterRegistry meterRegistry) { - return new MicrometerCapability(meterRegistry); + @ConditionalOnClass(name = "feign.micrometer.MicrometerObservationCapability") + @ConditionalOnBean(type = "io.micrometer.observation.ObservationRegistry") + public MicrometerObservationCapability micrometerObservationCapability(ObservationRegistry registry) { + return new MicrometerObservationCapability(registry); + } + + @Bean + @ConditionalOnClass(name = "feign.micrometer.MicrometerCapability") + @ConditionalOnBean(type = "io.micrometer.core.instrument.MeterRegistry") + @ConditionalOnMissingBean({ MicrometerCapability.class, MicrometerObservationCapability.class }) + public MicrometerCapability micrometerCapability(MeterRegistry registry) { + return new MicrometerCapability(registry); } } diff --git a/spring-cloud-openfeign-core/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-openfeign-core/src/main/resources/META-INF/additional-spring-configuration-metadata.json index c7b48d294..8e90d1bd4 100644 --- a/spring-cloud-openfeign-core/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-openfeign-core/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -57,9 +57,9 @@ "defaultValue": "false" }, { - "name": "spring.cloud.openfeign.metrics.enabled", + "name": "spring.cloud.openfeign.micrometer.enabled", "type": "java.lang.Boolean", - "description": "Enables metrics capability for Feign.", + "description": "Enables Micrometer capabilities for Feign.", "defaultValue": "true" }, { diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientConfigurationTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientConfigurationTests.java index 100172afa..343b736fb 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientConfigurationTests.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientConfigurationTests.java @@ -69,7 +69,7 @@ void shouldDefaultToValuesWhenFieldsNotSet() { assertThat(config.getExceptionPropagationPolicy()).isNull(); assertThat(config.getCapabilities()).isNull(); assertThat(config.getQueryMapEncoder()).isNull(); - assertThat(config.getMetrics()).isNull(); + assertThat(config.getMicrometer()).isNull(); } @Test @@ -94,8 +94,8 @@ void shouldReturnValuesWhenSet() { List> capabilities = Lists.list(Capability.class); config.setCapabilities(capabilities); config.setQueryMapEncoder(QueryMapEncoder.class); - FeignClientProperties.MetricsProperties metrics = new FeignClientProperties.MetricsProperties(); - config.setMetrics(metrics); + FeignClientProperties.MicrometerProperties micrometer = new FeignClientProperties.MicrometerProperties(); + config.setMicrometer(micrometer); assertThat(config.getLoggerLevel()).isSameAs(Logger.Level.FULL); assertThat(config.getConnectTimeout()).isEqualTo(21); @@ -112,7 +112,7 @@ void shouldReturnValuesWhenSet() { assertThat(config.getExceptionPropagationPolicy()).isSameAs(ExceptionPropagationPolicy.UNWRAP); assertThat(config.getCapabilities()).isSameAs(capabilities); assertThat(config.getQueryMapEncoder()).isSameAs(QueryMapEncoder.class); - assertThat(config.getMetrics()).isSameAs(metrics); + assertThat(config.getMicrometer()).isSameAs(micrometer); } /** diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientDisabledClientLevelFeaturesTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientDisabledClientLevelFeaturesTests.java index 9e8a74ee6..abf946f9b 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientDisabledClientLevelFeaturesTests.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientDisabledClientLevelFeaturesTests.java @@ -22,6 +22,7 @@ import feign.Contract; import feign.RequestLine; import feign.micrometer.MicrometerCapability; +import feign.micrometer.MicrometerObservationCapability; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -40,7 +41,7 @@ * @author Jonatan Ivanov */ @DirtiesContext -@ActiveProfiles("no-foo-metrics") +@ActiveProfiles("no-foo-micrometer") @SpringBootTest(classes = FeignClientDisabledClientLevelFeaturesTests.TestConfiguration.class) class FeignClientDisabledClientLevelFeaturesTests { @@ -62,12 +63,15 @@ void clientsAvailable() { @Test void capabilitiesShouldNotBeAvailableWhenDisabled() { assertThat(context.getInstance("foo", MicrometerCapability.class)).isNull(); + assertThat(context.getInstance("foo", MicrometerObservationCapability.class)).isNull(); assertThat(context.getInstances("foo", Capability.class)).isEmpty(); - assertThat(context.getInstance("bar", MicrometerCapability.class)).isNotNull(); + assertThat(context.getInstance("bar", MicrometerCapability.class)).isNull(); + assertThat(context.getInstance("bar", MicrometerObservationCapability.class)).isNotNull(); Map barCapabilities = context.getInstances("bar", Capability.class); assertThat(barCapabilities).hasSize(2); - assertThat(barCapabilities.get("micrometerCapability")).isExactlyInstanceOf(MicrometerCapability.class); + assertThat(barCapabilities.get("micrometerObservationCapability")) + .isExactlyInstanceOf(MicrometerObservationCapability.class); assertThat(barCapabilities.get("noOpCapability")).isExactlyInstanceOf(NoOpCapability.class); } diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientDisabledFeaturesTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientDisabledFeaturesTests.java index 7a829e03c..52b056313 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientDisabledFeaturesTests.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientDisabledFeaturesTests.java @@ -40,7 +40,7 @@ * @author Jonatan Ivanov */ @DirtiesContext -@ActiveProfiles("no-metrics") +@ActiveProfiles("no-micrometer") @SpringBootTest(classes = FeignClientDisabledFeaturesTests.TestConfiguration.class) class FeignClientDisabledFeaturesTests { diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientMetricsEnabledConditionTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientMicrometerEnabledConditionTests.java similarity index 88% rename from spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientMetricsEnabledConditionTests.java rename to spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientMicrometerEnabledConditionTests.java index 93eb6d806..47d30009a 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientMetricsEnabledConditionTests.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientMicrometerEnabledConditionTests.java @@ -42,7 +42,7 @@ * @author Jonatan Ivanov */ @ExtendWith({ MockitoExtension.class }) -class FeignClientMetricsEnabledConditionTests { +class FeignClientMicrometerEnabledConditionTests { @Mock private ConditionContext context; @@ -59,7 +59,7 @@ class FeignClientMetricsEnabledConditionTests { @Mock private Environment environment; - private final FeignClientMetricsEnabledCondition condition = new FeignClientMetricsEnabledCondition(); + private final FeignClientMicrometerEnabledCondition condition = new FeignClientMicrometerEnabledCondition(); @BeforeEach void setUp() { @@ -142,7 +142,7 @@ void shouldMatchWhenConfigMapContainsNullConfig() { } @Test - void shouldMatchWhenMetricsConfigurationIsMissing() { + void shouldMatchWhenMicrometerConfigurationIsMissing() { FeignClientProperties feignClientProperties = mock(FeignClientProperties.class); FeignClientProperties.FeignClientConfiguration feignClientConfig = mock( FeignClientProperties.FeignClientConfiguration.class); @@ -150,7 +150,7 @@ void shouldMatchWhenMetricsConfigurationIsMissing() { when(context.getEnvironment()).thenReturn(environment); when(environment.getProperty("spring.cloud.openfeign.client.name")).thenReturn("foo"); when(feignClientProperties.getConfig()).thenReturn(Maps.newHashMap("foo", feignClientConfig)); - when(feignClientConfig.getMetrics()).thenReturn(null); + when(feignClientConfig.getMicrometer()).thenReturn(null); assertThat(condition.matches(context, metadata)).isTrue(); verify(environment).getProperty("spring.cloud.openfeign.client.name"); @@ -165,7 +165,7 @@ void shouldMatchWhenEnabledFlagIsNotSet() { when(context.getEnvironment()).thenReturn(environment); when(environment.getProperty("spring.cloud.openfeign.client.name")).thenReturn("foo"); when(feignClientProperties.getConfig()).thenReturn(Maps.newHashMap("foo", feignClientConfig)); - when(feignClientConfig.getMetrics()).thenReturn(new FeignClientProperties.MetricsProperties()); + when(feignClientConfig.getMicrometer()).thenReturn(new FeignClientProperties.MicrometerProperties()); assertThat(condition.matches(context, metadata)).isTrue(); verify(environment).getProperty("spring.cloud.openfeign.client.name"); @@ -180,16 +180,16 @@ void shouldMatchWhenEnabledFlagIsNull() { when(context.getEnvironment()).thenReturn(environment); when(environment.getProperty("spring.cloud.openfeign.client.name")).thenReturn("foo"); when(feignClientProperties.getConfig()).thenReturn(Maps.newHashMap("foo", feignClientConfig)); - FeignClientProperties.MetricsProperties metricsProperties = new FeignClientProperties.MetricsProperties(); - metricsProperties.setEnabled(null); - when(feignClientConfig.getMetrics()).thenReturn(metricsProperties); + FeignClientProperties.MicrometerProperties micrometer = new FeignClientProperties.MicrometerProperties(); + micrometer.setEnabled(null); + when(feignClientConfig.getMicrometer()).thenReturn(micrometer); assertThat(condition.matches(context, metadata)).isTrue(); verify(environment).getProperty("spring.cloud.openfeign.client.name"); } @Test - void shouldMatchWhenMetricsConfigurationIsEnabled() { + void shouldMatchWhenMicrometerConfigurationIsEnabled() { FeignClientProperties feignClientProperties = mock(FeignClientProperties.class); FeignClientProperties.FeignClientConfiguration feignClientConfig = mock( FeignClientProperties.FeignClientConfiguration.class); @@ -197,16 +197,16 @@ void shouldMatchWhenMetricsConfigurationIsEnabled() { when(context.getEnvironment()).thenReturn(environment); when(environment.getProperty("spring.cloud.openfeign.client.name")).thenReturn("foo"); when(feignClientProperties.getConfig()).thenReturn(Maps.newHashMap("foo", feignClientConfig)); - FeignClientProperties.MetricsProperties metricsProperties = new FeignClientProperties.MetricsProperties(); - metricsProperties.setEnabled(true); - when(feignClientConfig.getMetrics()).thenReturn(metricsProperties); + FeignClientProperties.MicrometerProperties micrometer = new FeignClientProperties.MicrometerProperties(); + micrometer.setEnabled(true); + when(feignClientConfig.getMicrometer()).thenReturn(micrometer); assertThat(condition.matches(context, metadata)).isTrue(); verify(environment).getProperty("spring.cloud.openfeign.client.name"); } @Test - void shouldNotMatchWhenMetricsConfigurationIsEnabled() { + void shouldNotMatchWhenMicrometerConfigurationIsEnabled() { FeignClientProperties feignClientProperties = mock(FeignClientProperties.class); FeignClientProperties.FeignClientConfiguration feignClientConfig = mock( FeignClientProperties.FeignClientConfiguration.class); @@ -214,9 +214,9 @@ void shouldNotMatchWhenMetricsConfigurationIsEnabled() { when(context.getEnvironment()).thenReturn(environment); when(environment.getProperty("spring.cloud.openfeign.client.name")).thenReturn("foo"); when(feignClientProperties.getConfig()).thenReturn(Maps.newHashMap("foo", feignClientConfig)); - FeignClientProperties.MetricsProperties metricsProperties = new FeignClientProperties.MetricsProperties(); - metricsProperties.setEnabled(false); - when(feignClientConfig.getMetrics()).thenReturn(metricsProperties); + FeignClientProperties.MicrometerProperties micrometer = new FeignClientProperties.MicrometerProperties(); + micrometer.setEnabled(false); + when(feignClientConfig.getMicrometer()).thenReturn(micrometer); assertThat(condition.matches(context, metadata)).isFalse(); verify(environment).getProperty("spring.cloud.openfeign.client.name"); diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientOverrideDefaultsTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientOverrideDefaultsTests.java index 319f39811..cb0c5363b 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientOverrideDefaultsTests.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientOverrideDefaultsTests.java @@ -33,6 +33,7 @@ import feign.codec.Encoder; import feign.codec.ErrorDecoder; import feign.micrometer.MicrometerCapability; +import feign.micrometer.MicrometerObservationCapability; import feign.optionals.OptionalDecoder; import feign.querymap.BeanQueryMapEncoder; import feign.querymap.FieldQueryMapEncoder; @@ -149,19 +150,38 @@ void exceptionPropagationPolicy() { } @Test - void shouldOverrideMicrometerCapability() { + void shouldOverrideMicrometerCapabilities() { + // override micrometerCapability assertThat(context.getInstance("foo", MicrometerCapability.class)) .isExactlyInstanceOf(TestMicrometerCapability.class); + assertThat(context.getInstance("foo", MicrometerObservationCapability.class)) + .isExactlyInstanceOf(MicrometerObservationCapability.class); Map fooCapabilities = context.getInstances("foo", Capability.class); - assertThat(fooCapabilities).hasSize(1); + assertThat(fooCapabilities).hasSize(2); assertThat(fooCapabilities.get("micrometerCapability")).isExactlyInstanceOf(TestMicrometerCapability.class); + assertThat(fooCapabilities.get("micrometerObservationCapability")) + .isExactlyInstanceOf(MicrometerObservationCapability.class); - assertThat(context.getInstance("bar", MicrometerCapability.class)) - .isExactlyInstanceOf(TestMicrometerCapability.class); + // override micrometerObservationCapability + assertThat(context.getInstance("bar", MicrometerObservationCapability.class)) + .isExactlyInstanceOf(TestMicrometerObservationCapability.class); Map barCapabilities = context.getInstances("bar", Capability.class); - assertThat(barCapabilities).hasSize(2); - assertThat(barCapabilities.get("micrometerCapability")).isExactlyInstanceOf(TestMicrometerCapability.class); - assertThat(barCapabilities.get("noOpCapability")).isExactlyInstanceOf(NoOpCapability.class); + assertThat(barCapabilities).hasSize(1); + assertThat(barCapabilities.get("micrometerCapability")).isNull(); + assertThat(barCapabilities.get("micrometerObservationCapability")) + .isExactlyInstanceOf(TestMicrometerObservationCapability.class); + + // override both + an extra capability + assertThat(context.getInstance("baz", MicrometerCapability.class)) + .isExactlyInstanceOf(TestMicrometerCapability.class); + assertThat(context.getInstance("baz", MicrometerObservationCapability.class)) + .isExactlyInstanceOf(TestMicrometerObservationCapability.class); + Map bazCapabilities = context.getInstances("baz", Capability.class); + assertThat(bazCapabilities).hasSize(3); + assertThat(bazCapabilities.get("micrometerCapability")).isExactlyInstanceOf(TestMicrometerCapability.class); + assertThat(bazCapabilities.get("micrometerObservationCapability")) + .isExactlyInstanceOf(TestMicrometerObservationCapability.class); + assertThat(bazCapabilities.get("noOpCapability")).isExactlyInstanceOf(NoOpCapability.class); } @FeignClient(name = "foo", url = "https://foo", configuration = FooConfiguration.class) @@ -180,8 +200,16 @@ interface BarClient { } + @FeignClient(name = "baz", url = "https://baz", configuration = BazConfiguration.class) + interface BazClient { + + @GetMapping("/baz") + String get(); + + } + @Configuration(proxyBeanMethods = false) - @EnableFeignClients(clients = { FooClient.class, BarClient.class }) + @EnableFeignClients(clients = { FooClient.class, BarClient.class, BazClient.class }) @EnableAutoConfiguration protected static class TestConfiguration { @@ -191,43 +219,43 @@ RequestInterceptor defaultRequestInterceptor() { }; } - @Bean - MicrometerCapability micrometerCapability() { - return new TestMicrometerCapability(); - } - } - public static class FooConfiguration { + static class FooConfiguration { @Bean - public Decoder feignDecoder() { + Decoder feignDecoder() { return new Decoder.Default(); } @Bean - public Encoder feignEncoder() { + Encoder feignEncoder() { return new Encoder.Default(); } @Bean - public Logger feignLogger() { + Logger feignLogger() { return new Logger.JavaLogger(FooConfiguration.class); } @Bean - public Contract feignContract() { + Contract feignContract() { return new Contract.Default(); } @Bean - public QueryMapEncoder queryMapEncoder() { + QueryMapEncoder queryMapEncoder() { return new FieldQueryMapEncoder(); } + @Bean + MicrometerCapability micrometerCapability() { + return new TestMicrometerCapability(); + } + } - public static class BarConfiguration { + static class BarConfiguration { @Bean Logger.Level feignLevel() { @@ -255,22 +283,49 @@ RequestInterceptor feignRequestInterceptor() { } @Bean - public QueryMapEncoder queryMapEncoder() { + QueryMapEncoder queryMapEncoder() { return new BeanQueryMapEncoder(); } @Bean - public ExceptionPropagationPolicy exceptionPropagationPolicy() { + ExceptionPropagationPolicy exceptionPropagationPolicy() { return ExceptionPropagationPolicy.UNWRAP; } @Bean - public Capability noOpCapability() { + MicrometerObservationCapability micrometerObservationCapability() { + return new TestMicrometerObservationCapability(); + } + + } + + static class BazConfiguration { + + @Bean + MicrometerObservationCapability micrometerObservationCapability() { + return new TestMicrometerObservationCapability(); + } + + @Bean + MicrometerCapability micrometerCapability() { + return new TestMicrometerCapability(); + } + + @Bean + Capability noOpCapability() { return new NoOpCapability(); } } + private static class TestMicrometerObservationCapability extends feign.micrometer.MicrometerObservationCapability { + + TestMicrometerObservationCapability() { + super(null); + } + + } + private static class TestMicrometerCapability extends feign.micrometer.MicrometerCapability { } diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientUsingConfigurerTest.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientUsingConfigurerTest.java index 935b806df..da4f2cf8c 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientUsingConfigurerTest.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientUsingConfigurerTest.java @@ -23,7 +23,7 @@ import feign.Feign; import feign.Logger; import feign.RequestInterceptor; -import feign.micrometer.MicrometerCapability; +import feign.micrometer.MicrometerObservationCapability; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -71,7 +71,7 @@ void testFeignClient() { List capabilities = (List) getBuilderValue(builder, "capabilities"); assertThat(capabilities).hasSize(2).hasAtLeastOneElementOfType(NoOpCapability.class) - .hasAtLeastOneElementOfType(MicrometerCapability.class); + .hasAtLeastOneElementOfType(MicrometerObservationCapability.class); } private Object getBuilderValue(Feign.Builder builder, String member) { @@ -95,7 +95,7 @@ void testNoInheritFeignClient() { List capabilities = (List) getBuilderValue(builder, "capabilities"); assertThat(capabilities).hasSize(2).hasAtLeastOneElementOfType(NoOpCapability.class) - .hasAtLeastOneElementOfType(MicrometerCapability.class); + .hasAtLeastOneElementOfType(MicrometerObservationCapability.class); } @SuppressWarnings("unchecked") @@ -110,7 +110,7 @@ void testNoInheritFeignClient_ignoreProperties() { List capabilities = (List) getBuilderValue(builder, "capabilities"); assertThat(capabilities).hasSize(2).hasAtLeastOneElementOfType(NoOpCapability.class) - .hasAtLeastOneElementOfType(MicrometerCapability.class); + .hasAtLeastOneElementOfType(MicrometerObservationCapability.class); } @EnableAutoConfiguration diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientUsingPropertiesTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientUsingPropertiesTests.java index a8f41ff49..6ff8d4022 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientUsingPropertiesTests.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientUsingPropertiesTests.java @@ -44,7 +44,7 @@ import feign.codec.EncodeException; import feign.codec.Encoder; import feign.codec.ErrorDecoder; -import feign.micrometer.MicrometerCapability; +import feign.micrometer.MicrometerObservationCapability; import jakarta.servlet.http.HttpServletRequest; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledForJreRange; @@ -244,7 +244,7 @@ public void clientShouldContainCapabilities() { assertThat(response).isEqualTo("OK"); List capabilities = (List) ReflectionTestUtils.getField(feignBuilder, "capabilities"); assertThat(capabilities).hasSize(2).hasAtLeastOneElementOfType(NoOpCapability.class) - .hasAtLeastOneElementOfType(MicrometerCapability.class); + .hasAtLeastOneElementOfType(MicrometerObservationCapability.class); } @Test diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/GzipDecodingTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/GzipDecodingTests.java index 181ff6468..a7496ff21 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/GzipDecodingTests.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/GzipDecodingTests.java @@ -44,7 +44,7 @@ value = { "spring.application.name=defaultGzipDecoderTests", "spring.cloud.openfeign.compression.response.enabled=true", "spring.cloud.openfeign.client.config.default.loggerLevel=none", - "spring.cloud.openfeign.metrics.enabled=false", + "spring.cloud.openfeign.micrometer.enabled=false", "logging.level.org.springframework.cloud.openfeign=DEBUG" }) @DirtiesContext class GzipDecodingTests extends FeignClientFactoryBean { diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/MetricsPropertiesTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/MicrometerPropertiesTests.java similarity index 76% rename from spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/MetricsPropertiesTests.java rename to spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/MicrometerPropertiesTests.java index 0ca56a146..455f1ae52 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/MetricsPropertiesTests.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/MicrometerPropertiesTests.java @@ -27,19 +27,21 @@ import static org.springframework.cloud.openfeign.test.EqualsAndHashCodeAssert.assertHashCodeConsistency; /** + * Tests for {@link FeignClientProperties.MicrometerProperties} + * * @author Jonatan Ivanov */ -class MetricsPropertiesTests { +class MicrometerPropertiesTests { @Test void shouldBeEnabledByDefault() { - FeignClientProperties.MetricsProperties properties = new FeignClientProperties.MetricsProperties(); + FeignClientProperties.MicrometerProperties properties = new FeignClientProperties.MicrometerProperties(); assertThat(properties.getEnabled()).isTrue(); } @Test void shouldBeDisabledWhenSet() { - FeignClientProperties.MetricsProperties properties = new FeignClientProperties.MetricsProperties(); + FeignClientProperties.MicrometerProperties properties = new FeignClientProperties.MicrometerProperties(); properties.setEnabled(false); assertThat(properties.getEnabled()).isFalse(); } @@ -50,10 +52,10 @@ void shouldBeDisabledWhenSet() { */ @Test void shouldHaveSomewhatValidEqualsAndHashCode() { - FeignClientProperties.MetricsProperties propertyOne = new FeignClientProperties.MetricsProperties(); - FeignClientProperties.MetricsProperties propertyTwo = new FeignClientProperties.MetricsProperties(); - FeignClientProperties.MetricsProperties propertyThree = new FeignClientProperties.MetricsProperties(); - FeignClientProperties.MetricsProperties differentProperty = new FeignClientProperties.MetricsProperties(); + FeignClientProperties.MicrometerProperties propertyOne = new FeignClientProperties.MicrometerProperties(); + FeignClientProperties.MicrometerProperties propertyTwo = new FeignClientProperties.MicrometerProperties(); + FeignClientProperties.MicrometerProperties propertyThree = new FeignClientProperties.MicrometerProperties(); + FeignClientProperties.MicrometerProperties differentProperty = new FeignClientProperties.MicrometerProperties(); differentProperty.setEnabled(false); assertEqualsReflexivity(propertyOne); diff --git a/spring-cloud-openfeign-core/src/test/resources/application.yml b/spring-cloud-openfeign-core/src/test/resources/application.yml index 2ad7ebb6f..fcb7c398f 100644 --- a/spring-cloud-openfeign-core/src/test/resources/application.yml +++ b/spring-cloud-openfeign-core/src/test/resources/application.yml @@ -23,9 +23,9 @@ feignClient: management.endpoints.web.expose: '*' --- -spring.config.activate.on-profile: no-metrics -spring.cloud.openfeign.metrics.enabled: false +spring.config.activate.on-profile: no-micrometer +spring.cloud.openfeign.micrometer.enabled: false --- -spring.config.activate.on-profile: no-foo-metrics -spring.cloud.openfeign.client.config.foo.metrics.enabled: false +spring.config.activate.on-profile: no-foo-micrometer +spring.cloud.openfeign.client.config.foo.micrometer.enabled: false From 5e250b8d35aa16b466c6916bf8fc5d170a62bba9 Mon Sep 17 00:00:00 2001 From: Jonatan Ivanov Date: Fri, 18 Nov 2022 21:42:13 -0800 Subject: [PATCH 2/2] Add tests for auto-configuration fro micrometer support --- ...ientsMicrometerAutoConfigurationTests.java | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientsMicrometerAutoConfigurationTests.java diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientsMicrometerAutoConfigurationTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientsMicrometerAutoConfigurationTests.java new file mode 100644 index 000000000..165ec71ca --- /dev/null +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientsMicrometerAutoConfigurationTests.java @@ -0,0 +1,85 @@ +/* + * Copyright 2022-2022 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.openfeign; + +import feign.micrometer.MicrometerCapability; +import feign.micrometer.MicrometerObservationCapability; +import org.junit.jupiter.api.Test; + +import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.FilteredClassLoader; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Micrometer auto-configuration tests for {@link FeignClientsConfiguration}. + * + * @author Jonatan Ivanov + */ +class FeignClientsMicrometerAutoConfigurationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration( + AutoConfigurations.of(ObservationAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class, + MetricsAutoConfiguration.class, FeignClientsConfiguration.class)); + + @Test + void shouldProvideMicrometerObservationCapability() { + contextRunner.run(context -> assertThat(context).hasSingleBean(MicrometerObservationCapability.class) + .doesNotHaveBean(MicrometerCapability.class)); + } + + @Test + void shouldNotProvideMicrometerObservationCapabilityIfFeatureIsDisabled() { + contextRunner.withPropertyValues("spring.cloud.openfeign.micrometer.enabled=false") + .run(context -> assertThat(context).doesNotHaveBean(MicrometerObservationCapability.class) + .doesNotHaveBean(MicrometerCapability.class)); + } + + @Test + void shouldProvideMicrometerCapabilityIfObservationRegistryIsMissing() { + new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(SimpleMetricsExportAutoConfiguration.class, + MetricsAutoConfiguration.class, FeignClientsConfiguration.class)) + .run(context -> assertThat(context).doesNotHaveBean(MicrometerObservationCapability.class) + .hasSingleBean(MicrometerCapability.class)); + } + + @Test + void shouldProvideMicrometerCapabilityIfMicrometerObservationCapabilityIsNotOnClasspath() { + contextRunner.withClassLoader(new FilteredClassLoader(MicrometerObservationCapability.class)) + .run(context -> assertThat(context).doesNotHaveBean(MicrometerObservationCapability.class) + .hasSingleBean(MicrometerCapability.class)); + } + + @Test + void shouldNotProvideMicrometerCapabilitiesIfMicrometerSupportIsMissing() { + contextRunner.withClassLoader(new FilteredClassLoader("feign.micrometer")).run(context -> assertThat(context) + .doesNotHaveBean(MicrometerObservationCapability.class).doesNotHaveBean(MicrometerCapability.class)); + } + + @Test + void shouldNotProvideMicrometerCapabilitiesIfBeansAreMissing() { + new ApplicationContextRunner().withConfiguration(AutoConfigurations.of(FeignClientsConfiguration.class)) + .run(context -> assertThat(context).doesNotHaveBean(MicrometerObservationCapability.class) + .doesNotHaveBean(MicrometerCapability.class)); + } + +}