Browse Source

Micrometer Observation API Support (#793)

pull/798/head
Jonatan Ivanov 2 years ago committed by GitHub
parent
commit
372a631c38
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      docs/src/main/asciidoc/_configprops.adoc
  2. 54
      docs/src/main/asciidoc/spring-cloud-openfeign.adoc
  3. 8
      spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientMicrometerEnabledCondition.java
  4. 21
      spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientProperties.java
  5. 24
      spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientsConfiguration.java
  6. 4
      spring-cloud-openfeign-core/src/main/resources/META-INF/additional-spring-configuration-metadata.json
  7. 8
      spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientConfigurationTests.java
  8. 10
      spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientDisabledClientLevelFeaturesTests.java
  9. 2
      spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientDisabledFeaturesTests.java
  10. 32
      spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientMicrometerEnabledConditionTests.java
  11. 101
      spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientOverrideDefaultsTests.java
  12. 8
      spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientUsingConfigurerTest.java
  13. 4
      spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientUsingPropertiesTests.java
  14. 85
      spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientsMicrometerAutoConfigurationTests.java
  15. 2
      spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/GzipDecodingTests.java
  16. 16
      spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/MicrometerPropertiesTests.java
  17. 8
      spring-cloud-openfeign-core/src/test/resources/application.yml

4
docs/src/main/asciidoc/_configprops.adoc

@ -29,9 +29,9 @@ @@ -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.
|===
|===

54
docs/src/main/asciidoc/spring-cloud-openfeign.adoc

@ -121,7 +121,8 @@ Spring Cloud OpenFeign provides the following beans by default for feign (`BeanT @@ -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 @@ -146,7 +147,7 @@ Spring Cloud OpenFeign _does not_ provide the following beans by default for fei
* `Collection<RequestInterceptor>`
* `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: @@ -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 { @@ -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 { @@ -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 { @@ -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 <<feign-metrics>>.
The support for Micrometer is a good real-life example for this. See <<micrometer-support>>.
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 { @@ -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]
----

8
spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientMetricsEnabledCondition.java → spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientMicrometerEnabledCondition.java

@ -25,7 +25,7 @@ import org.springframework.core.type.AnnotatedTypeMetadata; @@ -25,7 +25,7 @@ import org.springframework.core.type.AnnotatedTypeMetadata;
/**
* @author Jonatan Ivanov
*/
class FeignClientMetricsEnabledCondition implements Condition {
class FeignClientMicrometerEnabledCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
@ -38,9 +38,9 @@ class FeignClientMetricsEnabledCondition implements Condition { @@ -38,9 +38,9 @@ class FeignClientMetricsEnabledCondition implements Condition {
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();
}
}
}

21
spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientProperties.java

@ -144,7 +144,7 @@ public class FeignClientProperties { @@ -144,7 +144,7 @@ public class FeignClientProperties {
private Class<QueryMapEncoder> queryMapEncoder;
private MetricsProperties metrics;
private MicrometerProperties micrometer;
private Boolean followRedirects;
@ -274,12 +274,12 @@ public class FeignClientProperties { @@ -274,12 +274,12 @@ public class FeignClientProperties {
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 class FeignClientProperties { @@ -317,7 +317,8 @@ public class FeignClientProperties {
&& 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 class FeignClientProperties { @@ -325,15 +326,15 @@ public class FeignClientProperties {
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 class FeignClientProperties { @@ -354,7 +355,7 @@ public class FeignClientProperties {
return false;
}
MetricsProperties that = (MetricsProperties) o;
MicrometerProperties that = (MicrometerProperties) o;
return Objects.equals(enabled, that.enabled);
}

24
spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientsConfiguration.java

@ -29,8 +29,10 @@ import feign.codec.Encoder; @@ -29,8 +29,10 @@ import feign.codec.Encoder;
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 class FeignClientsConfiguration { @@ -235,16 +237,24 @@ public class FeignClientsConfiguration {
}
@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);
}
}

4
spring-cloud-openfeign-core/src/main/resources/META-INF/additional-spring-configuration-metadata.json

@ -57,9 +57,9 @@ @@ -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"
},
{

8
spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientConfigurationTests.java

@ -69,7 +69,7 @@ class FeignClientConfigurationTests { @@ -69,7 +69,7 @@ class FeignClientConfigurationTests {
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 @@ class FeignClientConfigurationTests { @@ -94,8 +94,8 @@ class FeignClientConfigurationTests {
List<Class<Capability>> 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 @@ class FeignClientConfigurationTests { @@ -112,7 +112,7 @@ class FeignClientConfigurationTests {
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);
}
/**

10
spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientDisabledClientLevelFeaturesTests.java

@ -22,6 +22,7 @@ import feign.Capability; @@ -22,6 +22,7 @@ import feign.Capability;
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 @@ import static org.assertj.core.api.Assertions.assertThat; @@ -40,7 +41,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Jonatan Ivanov
*/
@DirtiesContext
@ActiveProfiles("no-foo-metrics")
@ActiveProfiles("no-foo-micrometer")
@SpringBootTest(classes = FeignClientDisabledClientLevelFeaturesTests.TestConfiguration.class)
class FeignClientDisabledClientLevelFeaturesTests {
@ -62,12 +63,15 @@ class FeignClientDisabledClientLevelFeaturesTests { @@ -62,12 +63,15 @@ class FeignClientDisabledClientLevelFeaturesTests {
@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<String, Capability> 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);
}

2
spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientDisabledFeaturesTests.java

@ -40,7 +40,7 @@ import static org.assertj.core.api.Assertions.assertThat; @@ -40,7 +40,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Jonatan Ivanov
*/
@DirtiesContext
@ActiveProfiles("no-metrics")
@ActiveProfiles("no-micrometer")
@SpringBootTest(classes = FeignClientDisabledFeaturesTests.TestConfiguration.class)
class FeignClientDisabledFeaturesTests {

32
spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientMetricsEnabledConditionTests.java → spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientMicrometerEnabledConditionTests.java

@ -42,7 +42,7 @@ import static org.mockito.Mockito.when; @@ -42,7 +42,7 @@ import static org.mockito.Mockito.when;
* @author Jonatan Ivanov
*/
@ExtendWith({ MockitoExtension.class })
class FeignClientMetricsEnabledConditionTests {
class FeignClientMicrometerEnabledConditionTests {
@Mock
private ConditionContext context;
@ -59,7 +59,7 @@ class FeignClientMetricsEnabledConditionTests { @@ -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 @@ class FeignClientMetricsEnabledConditionTests { @@ -142,7 +142,7 @@ class FeignClientMetricsEnabledConditionTests {
}
@Test
void shouldMatchWhenMetricsConfigurationIsMissing() {
void shouldMatchWhenMicrometerConfigurationIsMissing() {
FeignClientProperties feignClientProperties = mock(FeignClientProperties.class);
FeignClientProperties.FeignClientConfiguration feignClientConfig = mock(
FeignClientProperties.FeignClientConfiguration.class);
@ -150,7 +150,7 @@ class FeignClientMetricsEnabledConditionTests { @@ -150,7 +150,7 @@ class FeignClientMetricsEnabledConditionTests {
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 @@ class FeignClientMetricsEnabledConditionTests { @@ -165,7 +165,7 @@ class FeignClientMetricsEnabledConditionTests {
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 @@ class FeignClientMetricsEnabledConditionTests { @@ -180,16 +180,16 @@ class FeignClientMetricsEnabledConditionTests {
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 @@ class FeignClientMetricsEnabledConditionTests { @@ -197,16 +197,16 @@ class FeignClientMetricsEnabledConditionTests {
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 @@ class FeignClientMetricsEnabledConditionTests { @@ -214,9 +214,9 @@ class FeignClientMetricsEnabledConditionTests {
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");

101
spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientOverrideDefaultsTests.java

@ -33,6 +33,7 @@ import feign.codec.Decoder; @@ -33,6 +33,7 @@ import feign.codec.Decoder;
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 @@ class FeignClientOverrideDefaultsTests { @@ -149,19 +150,38 @@ class FeignClientOverrideDefaultsTests {
}
@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<String, Capability> 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<String, Capability> 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<String, Capability> 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 @@ class FeignClientOverrideDefaultsTests { @@ -180,8 +200,16 @@ class FeignClientOverrideDefaultsTests {
}
@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 @@ class FeignClientOverrideDefaultsTests { @@ -191,43 +219,43 @@ class FeignClientOverrideDefaultsTests {
};
}
@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 @@ class FeignClientOverrideDefaultsTests { @@ -255,22 +283,49 @@ class FeignClientOverrideDefaultsTests {
}
@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 {
}

8
spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientUsingConfigurerTest.java

@ -23,7 +23,7 @@ import feign.Capability; @@ -23,7 +23,7 @@ import feign.Capability;
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 @@ class FeignClientUsingConfigurerTest { @@ -71,7 +71,7 @@ class FeignClientUsingConfigurerTest {
List<Capability> 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 @@ class FeignClientUsingConfigurerTest { @@ -95,7 +95,7 @@ class FeignClientUsingConfigurerTest {
List<Capability> capabilities = (List) getBuilderValue(builder, "capabilities");
assertThat(capabilities).hasSize(2).hasAtLeastOneElementOfType(NoOpCapability.class)
.hasAtLeastOneElementOfType(MicrometerCapability.class);
.hasAtLeastOneElementOfType(MicrometerObservationCapability.class);
}
@SuppressWarnings("unchecked")
@ -110,7 +110,7 @@ class FeignClientUsingConfigurerTest { @@ -110,7 +110,7 @@ class FeignClientUsingConfigurerTest {
List<Capability> capabilities = (List) getBuilderValue(builder, "capabilities");
assertThat(capabilities).hasSize(2).hasAtLeastOneElementOfType(NoOpCapability.class)
.hasAtLeastOneElementOfType(MicrometerCapability.class);
.hasAtLeastOneElementOfType(MicrometerObservationCapability.class);
}
@EnableAutoConfiguration

4
spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientUsingPropertiesTests.java

@ -44,7 +44,7 @@ import feign.Retryer; @@ -44,7 +44,7 @@ import feign.Retryer;
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 class FeignClientUsingPropertiesTests { @@ -244,7 +244,7 @@ public class FeignClientUsingPropertiesTests {
assertThat(response).isEqualTo("OK");
List<Capability> capabilities = (List) ReflectionTestUtils.getField(feignBuilder, "capabilities");
assertThat(capabilities).hasSize(2).hasAtLeastOneElementOfType(NoOpCapability.class)
.hasAtLeastOneElementOfType(MicrometerCapability.class);
.hasAtLeastOneElementOfType(MicrometerObservationCapability.class);
}
@Test

85
spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientsMicrometerAutoConfigurationTests.java

@ -0,0 +1,85 @@ @@ -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));
}
}

2
spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/GzipDecodingTests.java

@ -44,7 +44,7 @@ import static org.assertj.core.api.Assertions.assertThat; @@ -44,7 +44,7 @@ import static org.assertj.core.api.Assertions.assertThat;
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 {

16
spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/MetricsPropertiesTests.java → 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.a @@ -27,19 +27,21 @@ import static org.springframework.cloud.openfeign.test.EqualsAndHashCodeAssert.a
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 @@ class MetricsPropertiesTests { @@ -50,10 +52,10 @@ class MetricsPropertiesTests {
*/
@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);

8
spring-cloud-openfeign-core/src/test/resources/application.yml

@ -23,9 +23,9 @@ feignClient: @@ -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

Loading…
Cancel
Save