Micrometer Observation API Support (#793)
This commit is contained in:
@@ -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.
|
||||
|
||||
|===
|
||||
|===
|
||||
|
||||
@@ -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<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:
|
||||
- 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 <<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 {
|
||||
}
|
||||
----
|
||||
|
||||
=== 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]
|
||||
----
|
||||
|
||||
@@ -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 {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
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 {
|
||||
&& 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 {
|
||||
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 {
|
||||
return false;
|
||||
}
|
||||
|
||||
MetricsProperties that = (MetricsProperties) o;
|
||||
MicrometerProperties that = (MicrometerProperties) o;
|
||||
return Objects.equals(enabled, that.enabled);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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 {
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
* @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 {
|
||||
@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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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 {
|
||||
@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 {
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldMatchWhenMetricsConfigurationIsMissing() {
|
||||
void shouldMatchWhenMicrometerConfigurationIsMissing() {
|
||||
FeignClientProperties feignClientProperties = mock(FeignClientProperties.class);
|
||||
FeignClientProperties.FeignClientConfiguration feignClientConfig = mock(
|
||||
FeignClientProperties.FeignClientConfiguration.class);
|
||||
@@ -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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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");
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
@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 {
|
||||
|
||||
}
|
||||
|
||||
@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,6 +219,35 @@ class FeignClientOverrideDefaultsTests {
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class FooConfiguration {
|
||||
|
||||
@Bean
|
||||
Decoder feignDecoder() {
|
||||
return new Decoder.Default();
|
||||
}
|
||||
|
||||
@Bean
|
||||
Encoder feignEncoder() {
|
||||
return new Encoder.Default();
|
||||
}
|
||||
|
||||
@Bean
|
||||
Logger feignLogger() {
|
||||
return new Logger.JavaLogger(FooConfiguration.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
Contract feignContract() {
|
||||
return new Contract.Default();
|
||||
}
|
||||
|
||||
@Bean
|
||||
QueryMapEncoder queryMapEncoder() {
|
||||
return new FieldQueryMapEncoder();
|
||||
}
|
||||
|
||||
@Bean
|
||||
MicrometerCapability micrometerCapability() {
|
||||
return new TestMicrometerCapability();
|
||||
@@ -198,36 +255,7 @@ class FeignClientOverrideDefaultsTests {
|
||||
|
||||
}
|
||||
|
||||
public static class FooConfiguration {
|
||||
|
||||
@Bean
|
||||
public Decoder feignDecoder() {
|
||||
return new Decoder.Default();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Encoder feignEncoder() {
|
||||
return new Encoder.Default();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Logger feignLogger() {
|
||||
return new Logger.JavaLogger(FooConfiguration.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Contract feignContract() {
|
||||
return new Contract.Default();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public QueryMapEncoder queryMapEncoder() {
|
||||
return new FieldQueryMapEncoder();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class BarConfiguration {
|
||||
static class BarConfiguration {
|
||||
|
||||
@Bean
|
||||
Logger.Level feignLevel() {
|
||||
@@ -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 {
|
||||
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
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 {
|
||||
|
||||
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 {
|
||||
|
||||
List<Capability> capabilities = (List) getBuilderValue(builder, "capabilities");
|
||||
assertThat(capabilities).hasSize(2).hasAtLeastOneElementOfType(NoOpCapability.class)
|
||||
.hasAtLeastOneElementOfType(MicrometerCapability.class);
|
||||
.hasAtLeastOneElementOfType(MicrometerObservationCapability.class);
|
||||
}
|
||||
|
||||
@EnableAutoConfiguration
|
||||
|
||||
@@ -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 {
|
||||
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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
*/
|
||||
@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);
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user