Extract AutoTimer interface for metrics
Refactor `Autotime` from a properties object to an interface and change the existing metric recording implementations. The `AutoTimer` interface is a general purpose callback that can be applied to a `Timer.Builder` to configure it. Autotime properties are now located in `spring-boot-actuator-autoconfigure` and have become an implementation of the interface. Closes gh-17026
This commit is contained in:
parent
ad5e905bd7
commit
68a3fbd7a0
|
@ -14,18 +14,21 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.metrics;
|
||||
package org.springframework.boot.actuate.autoconfigure.metrics;
|
||||
|
||||
import java.util.List;
|
||||
import io.micrometer.core.instrument.Timer.Builder;
|
||||
|
||||
import org.springframework.boot.actuate.metrics.AutoTimer;
|
||||
|
||||
/**
|
||||
* Settings for requests that are automatically timed.
|
||||
* Nested configuration properties for items that are automatically timed.
|
||||
*
|
||||
* @author Tadaya Tsuyukubo
|
||||
* @author Stephane Nicoll
|
||||
* @author Phillip Webb
|
||||
* @since 2.2.0
|
||||
*/
|
||||
public final class Autotime {
|
||||
public final class AutoTimeProperties implements AutoTimer {
|
||||
|
||||
private boolean enabled = true;
|
||||
|
||||
|
@ -36,24 +39,10 @@ public final class Autotime {
|
|||
/**
|
||||
* Create an instance that automatically time requests with no percentiles.
|
||||
*/
|
||||
public Autotime() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance with the specified settings.
|
||||
* @param enabled whether requests should be automatically timed
|
||||
* @param percentilesHistogram whether percentile histograms should be published
|
||||
* @param percentiles computed non-aggregable percentiles to publish (can be
|
||||
* {@code null})
|
||||
*/
|
||||
public Autotime(boolean enabled, boolean percentilesHistogram,
|
||||
List<Double> percentiles) {
|
||||
this.enabled = enabled;
|
||||
this.percentilesHistogram = percentilesHistogram;
|
||||
this.percentiles = (percentiles != null)
|
||||
? percentiles.stream().mapToDouble(Double::doubleValue).toArray() : null;
|
||||
public AutoTimeProperties() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
|
@ -78,12 +67,10 @@ public final class Autotime {
|
|||
this.percentiles = percentiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance that disable auto-timed requests.
|
||||
* @return an instance that disable auto-timed requests
|
||||
*/
|
||||
public static Autotime disabled() {
|
||||
return new Autotime(false, false, null);
|
||||
@Override
|
||||
public void apply(Builder builder) {
|
||||
builder.publishPercentileHistogram(this.percentilesHistogram)
|
||||
.publishPercentiles(this.percentiles);
|
||||
}
|
||||
|
||||
}
|
|
@ -19,7 +19,6 @@ package org.springframework.boot.actuate.autoconfigure.metrics;
|
|||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.actuate.metrics.Autotime;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.DeprecatedConfigurationProperty;
|
||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||
|
@ -116,6 +115,7 @@ public class MetricsProperties {
|
|||
* @return request metric name
|
||||
* @deprecated since 2.2.0 in favor of {@link ClientRequest#getMetricName()}
|
||||
*/
|
||||
@Deprecated
|
||||
@DeprecatedConfigurationProperty(
|
||||
replacement = "management.metrics.web.client.request.metric-name")
|
||||
public String getRequestsMetricName() {
|
||||
|
@ -128,6 +128,7 @@ public class MetricsProperties {
|
|||
* @deprecated since 2.2.0 in favor of
|
||||
* {@link ClientRequest#setMetricName(String)}
|
||||
*/
|
||||
@Deprecated
|
||||
public void setRequestsMetricName(String requestsMetricName) {
|
||||
this.request.setMetricName(requestsMetricName);
|
||||
}
|
||||
|
@ -151,10 +152,10 @@ public class MetricsProperties {
|
|||
* Auto-timed request settings.
|
||||
*/
|
||||
@NestedConfigurationProperty
|
||||
private final Autotime autoTime = new Autotime();
|
||||
private final AutoTimeProperties autotime = new AutoTimeProperties();
|
||||
|
||||
public Autotime getAutotime() {
|
||||
return this.autoTime;
|
||||
public AutoTimeProperties getAutotime() {
|
||||
return this.autotime;
|
||||
}
|
||||
|
||||
public String getMetricName() {
|
||||
|
@ -187,7 +188,7 @@ public class MetricsProperties {
|
|||
/**
|
||||
* Return whether server requests should be automatically timed.
|
||||
* @return {@code true} if server request should be automatically timed
|
||||
* @deprecated since 2.2.0 in favor of {@link Autotime#isEnabled()}
|
||||
* @deprecated since 2.2.0 in favor of {@link AutoTimeProperties#isEnabled()}
|
||||
*/
|
||||
@DeprecatedConfigurationProperty(
|
||||
replacement = "management.metrics.web.server.request.autotime.enabled")
|
||||
|
@ -200,7 +201,7 @@ public class MetricsProperties {
|
|||
* Set whether server requests should be automatically timed.
|
||||
* @param autoTimeRequests whether server requests should be automatically
|
||||
* timed
|
||||
* @deprecated since 2.2.0 in favor of {@link Autotime#isEnabled()}
|
||||
* @deprecated since 2.2.0 in favor of {@link AutoTimeProperties#isEnabled()}
|
||||
*/
|
||||
@Deprecated
|
||||
public void setAutoTimeRequests(boolean autoTimeRequests) {
|
||||
|
@ -249,9 +250,9 @@ public class MetricsProperties {
|
|||
* Auto-timed request settings.
|
||||
*/
|
||||
@NestedConfigurationProperty
|
||||
private final Autotime autotime = new Autotime();
|
||||
private final AutoTimeProperties autotime = new AutoTimeProperties();
|
||||
|
||||
public Autotime getAutotime() {
|
||||
public AutoTimeProperties getAutotime() {
|
||||
return this.autotime;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright 2012-2019 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.boot.actuate.metrics;
|
||||
/**
|
||||
* @author pwebb
|
||||
*/
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import io.micrometer.core.annotation.Timed;
|
||||
import io.micrometer.core.instrument.Timer;
|
||||
import io.micrometer.core.instrument.Timer.Builder;
|
||||
|
||||
/**
|
||||
* Strategy that can be used to apply {@link Timer Timers} automatically instead of using
|
||||
* {@link Timed @Timed}.
|
||||
*
|
||||
* @author Tadaya Tsuyukubo
|
||||
* @author Stephane Nicoll
|
||||
* @author Phillip Webb
|
||||
* @since 2.2.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface AutoTimer {
|
||||
|
||||
/**
|
||||
* An {@link AutoTimer} implementation that is enabled but applies no additional
|
||||
* customizations.
|
||||
*/
|
||||
AutoTimer ENABLED = (builder) -> {
|
||||
};
|
||||
|
||||
/**
|
||||
* An {@link AutoTimer} implementation that is disabled and will not record metrics.
|
||||
*/
|
||||
AutoTimer DISABLED = new AutoTimer() {
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(Builder builder) {
|
||||
throw new IllegalStateException("AutoTimer is disabled");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Return if the auto-timer is enabled and metrics should be recorded.
|
||||
* @return if the auto-timer is enabled
|
||||
*/
|
||||
default boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create a new {@link Builder Timer.Builder} with auto-timer
|
||||
* settings {@link #apply(Builder) applied}.
|
||||
* @param name the name of the timer
|
||||
* @return a new builder instance with auto-settings applied
|
||||
*/
|
||||
default Timer.Builder builder(String name) {
|
||||
return builder(() -> Timer.builder(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create a new {@link Builder Timer.Builder} with auto-timer
|
||||
* settings {@link #apply(Builder) applied}.
|
||||
* @param supplier the builder supplier
|
||||
* @return a new builder instance with auto-settings applied
|
||||
*/
|
||||
default Timer.Builder builder(Supplier<Timer.Builder> supplier) {
|
||||
Timer.Builder builder = supplier.get();
|
||||
apply(builder);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to apply any auto-timer settings to the given {@link Builder Timer.Builder}.
|
||||
* @param builder the builder to apply settings to
|
||||
*/
|
||||
void apply(Timer.Builder builder);
|
||||
|
||||
}
|
|
@ -24,7 +24,7 @@ import java.util.concurrent.TimeUnit;
|
|||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.Timer;
|
||||
|
||||
import org.springframework.boot.actuate.metrics.Autotime;
|
||||
import org.springframework.boot.actuate.metrics.AutoTimer;
|
||||
import org.springframework.core.NamedThreadLocal;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.http.client.ClientHttpRequestExecution;
|
||||
|
@ -51,7 +51,7 @@ class MetricsClientHttpRequestInterceptor implements ClientHttpRequestIntercepto
|
|||
|
||||
private final String metricName;
|
||||
|
||||
private final Autotime autotime;
|
||||
private final AutoTimer autoTimer;
|
||||
|
||||
/**
|
||||
* Create a new {@code MetricsClientHttpRequestInterceptor}.
|
||||
|
@ -59,11 +59,12 @@ class MetricsClientHttpRequestInterceptor implements ClientHttpRequestIntercepto
|
|||
* @param tagProvider provider for metrics tags
|
||||
* @param metricName name of the metric to record
|
||||
* @deprecated since 2.2.0 in favor of
|
||||
* {@link #MetricsClientHttpRequestInterceptor(MeterRegistry, RestTemplateExchangeTagsProvider, String, Autotime)}
|
||||
* {@link #MetricsClientHttpRequestInterceptor(MeterRegistry, RestTemplateExchangeTagsProvider, String, AutoTimer)}
|
||||
*/
|
||||
@Deprecated
|
||||
MetricsClientHttpRequestInterceptor(MeterRegistry meterRegistry,
|
||||
RestTemplateExchangeTagsProvider tagProvider, String metricName) {
|
||||
this(meterRegistry, tagProvider, metricName, new Autotime());
|
||||
this(meterRegistry, tagProvider, metricName, AutoTimer.ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -71,21 +72,24 @@ class MetricsClientHttpRequestInterceptor implements ClientHttpRequestIntercepto
|
|||
* @param meterRegistry the registry to which metrics are recorded
|
||||
* @param tagProvider provider for metrics tags
|
||||
* @param metricName name of the metric to record
|
||||
* @param autotime auto timed request settings
|
||||
* @param autoTimer the auto-timers to apply or {@code null} to disable auto-timing
|
||||
* @since 2.2.0
|
||||
*/
|
||||
MetricsClientHttpRequestInterceptor(MeterRegistry meterRegistry,
|
||||
RestTemplateExchangeTagsProvider tagProvider, String metricName,
|
||||
Autotime autotime) {
|
||||
AutoTimer autoTimer) {
|
||||
this.tagProvider = tagProvider;
|
||||
this.meterRegistry = meterRegistry;
|
||||
this.metricName = metricName;
|
||||
this.autotime = (autotime != null) ? autotime : Autotime.disabled();
|
||||
this.autoTimer = (autoTimer != null) ? autoTimer : AutoTimer.DISABLED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientHttpResponse intercept(HttpRequest request, byte[] body,
|
||||
ClientHttpRequestExecution execution) throws IOException {
|
||||
if (!this.autoTimer.isEnabled()) {
|
||||
return execution.execute(request, body);
|
||||
}
|
||||
long startTime = System.nanoTime();
|
||||
ClientHttpResponse response = null;
|
||||
try {
|
||||
|
@ -93,10 +97,8 @@ class MetricsClientHttpRequestInterceptor implements ClientHttpRequestIntercepto
|
|||
return response;
|
||||
}
|
||||
finally {
|
||||
if (this.autotime.isEnabled()) {
|
||||
getTimeBuilder(request, response).register(this.meterRegistry)
|
||||
.record(System.nanoTime() - startTime, TimeUnit.NANOSECONDS);
|
||||
}
|
||||
getTimeBuilder(request, response).register(this.meterRegistry)
|
||||
.record(System.nanoTime() - startTime, TimeUnit.NANOSECONDS);
|
||||
urlTemplate.remove();
|
||||
}
|
||||
}
|
||||
|
@ -121,9 +123,7 @@ class MetricsClientHttpRequestInterceptor implements ClientHttpRequestIntercepto
|
|||
|
||||
private Timer.Builder getTimeBuilder(HttpRequest request,
|
||||
ClientHttpResponse response) {
|
||||
return Timer.builder(this.metricName)
|
||||
.publishPercentiles(this.autotime.getPercentiles())
|
||||
.publishPercentileHistogram(this.autotime.isPercentilesHistogram())
|
||||
return this.autoTimer.builder(this.metricName)
|
||||
.tags(this.tagProvider.getTags(urlTemplate.get(), request, response))
|
||||
.description("Timer of RestTemplate operation");
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ import java.util.List;
|
|||
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
|
||||
import org.springframework.boot.actuate.metrics.Autotime;
|
||||
import org.springframework.boot.actuate.metrics.AutoTimer;
|
||||
import org.springframework.boot.web.client.RestTemplateCustomizer;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
@ -47,29 +47,30 @@ public class MetricsRestTemplateCustomizer implements RestTemplateCustomizer {
|
|||
* @param tagProvider the tag provider
|
||||
* @param metricName the name of the recorded metric
|
||||
* @deprecated since 2.2.0 in favor of
|
||||
* {@link #MetricsRestTemplateCustomizer(MeterRegistry, RestTemplateExchangeTagsProvider, String, Autotime)}
|
||||
* {@link #MetricsRestTemplateCustomizer(MeterRegistry, RestTemplateExchangeTagsProvider, String, AutoTimer)}
|
||||
*/
|
||||
@Deprecated
|
||||
public MetricsRestTemplateCustomizer(MeterRegistry meterRegistry,
|
||||
RestTemplateExchangeTagsProvider tagProvider, String metricName) {
|
||||
this(meterRegistry, tagProvider, metricName, new Autotime());
|
||||
this(meterRegistry, tagProvider, metricName, AutoTimer.ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code MetricsRestTemplateInterceptor}. When {@code autoTimeRequests}
|
||||
* is set to {@code true}, the interceptor records metrics using the given
|
||||
* {@code meterRegistry} with tags provided by the given {@code tagProvider} and with
|
||||
* {@link Autotime auto-timed request configuration}.
|
||||
* {@link AutoTimer auto-timed configuration}.
|
||||
* @param meterRegistry the meter registry
|
||||
* @param tagProvider the tag provider
|
||||
* @param metricName the name of the recorded metric
|
||||
* @param autotime auto-timed request settings
|
||||
* @param autoTimer the auto-timers to apply or {@code null} to disable auto-timing
|
||||
* @since 2.2.0
|
||||
*/
|
||||
public MetricsRestTemplateCustomizer(MeterRegistry meterRegistry,
|
||||
RestTemplateExchangeTagsProvider tagProvider, String metricName,
|
||||
Autotime autotime) {
|
||||
AutoTimer autoTimer) {
|
||||
this.interceptor = new MetricsClientHttpRequestInterceptor(meterRegistry,
|
||||
tagProvider, metricName, autotime);
|
||||
tagProvider, metricName, autoTimer);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -18,7 +18,7 @@ package org.springframework.boot.actuate.metrics.web.reactive.client;
|
|||
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
|
||||
import org.springframework.boot.actuate.metrics.Autotime;
|
||||
import org.springframework.boot.actuate.metrics.AutoTimer;
|
||||
import org.springframework.boot.web.reactive.function.client.WebClientCustomizer;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
|
@ -41,12 +41,12 @@ public class MetricsWebClientCustomizer implements WebClientCustomizer {
|
|||
* @param tagProvider the tag provider
|
||||
* @param metricName the name of the recorded metric
|
||||
* @deprecated since 2.2.0 in favor of
|
||||
* {@link #MetricsWebClientCustomizer(MeterRegistry, WebClientExchangeTagsProvider, String, Autotime)}
|
||||
* {@link #MetricsWebClientCustomizer(MeterRegistry, WebClientExchangeTagsProvider, String, AutoTimer)}
|
||||
*/
|
||||
@Deprecated
|
||||
public MetricsWebClientCustomizer(MeterRegistry meterRegistry,
|
||||
WebClientExchangeTagsProvider tagProvider, String metricName) {
|
||||
this(meterRegistry, tagProvider, metricName, new Autotime());
|
||||
this(meterRegistry, tagProvider, metricName, AutoTimer.ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -56,14 +56,14 @@ public class MetricsWebClientCustomizer implements WebClientCustomizer {
|
|||
* @param meterRegistry the meter registry
|
||||
* @param tagProvider the tag provider
|
||||
* @param metricName the name of the recorded metric
|
||||
* @param autotime auto-timed request settings
|
||||
* @param autoTimer the auto-timers to apply or {@code null} to disable auto-timing
|
||||
* @since 2.2.0
|
||||
*/
|
||||
public MetricsWebClientCustomizer(MeterRegistry meterRegistry,
|
||||
WebClientExchangeTagsProvider tagProvider, String metricName,
|
||||
Autotime autotime) {
|
||||
AutoTimer autoTimer) {
|
||||
this.filterFunction = new MetricsWebClientFilterFunction(meterRegistry,
|
||||
tagProvider, metricName, autotime);
|
||||
tagProvider, metricName, autoTimer);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -20,10 +20,10 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.Tag;
|
||||
import io.micrometer.core.instrument.Timer;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.util.context.Context;
|
||||
|
||||
import org.springframework.boot.actuate.metrics.Autotime;
|
||||
import org.springframework.boot.actuate.metrics.AutoTimer;
|
||||
import org.springframework.web.reactive.function.client.ClientRequest;
|
||||
import org.springframework.web.reactive.function.client.ClientResponse;
|
||||
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
|
||||
|
@ -48,7 +48,7 @@ public class MetricsWebClientFilterFunction implements ExchangeFilterFunction {
|
|||
|
||||
private final String metricName;
|
||||
|
||||
private final Autotime autotime;
|
||||
private final AutoTimer autoTimer;
|
||||
|
||||
/**
|
||||
* Create a new {@code MetricsWebClientFilterFunction}.
|
||||
|
@ -56,12 +56,12 @@ public class MetricsWebClientFilterFunction implements ExchangeFilterFunction {
|
|||
* @param tagProvider provider for metrics tags
|
||||
* @param metricName name of the metric to record
|
||||
* @deprecated since 2.2.0 in favor of
|
||||
* {@link #MetricsWebClientFilterFunction(MeterRegistry, WebClientExchangeTagsProvider, String, Autotime)}
|
||||
* {@link #MetricsWebClientFilterFunction(MeterRegistry, WebClientExchangeTagsProvider, String, AutoTimer)}
|
||||
*/
|
||||
@Deprecated
|
||||
public MetricsWebClientFilterFunction(MeterRegistry meterRegistry,
|
||||
WebClientExchangeTagsProvider tagProvider, String metricName) {
|
||||
this(meterRegistry, tagProvider, metricName, new Autotime());
|
||||
this(meterRegistry, tagProvider, metricName, AutoTimer.ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -69,38 +69,43 @@ public class MetricsWebClientFilterFunction implements ExchangeFilterFunction {
|
|||
* @param meterRegistry the registry to which metrics are recorded
|
||||
* @param tagProvider provider for metrics tags
|
||||
* @param metricName name of the metric to record
|
||||
* @param autotime auto-timed request settings
|
||||
* @param autoTimer the auto-timer configuration or {@code null} to disable
|
||||
* @since 2.2.0
|
||||
*/
|
||||
public MetricsWebClientFilterFunction(MeterRegistry meterRegistry,
|
||||
WebClientExchangeTagsProvider tagProvider, String metricName,
|
||||
Autotime autotime) {
|
||||
AutoTimer autoTimer) {
|
||||
this.meterRegistry = meterRegistry;
|
||||
this.tagProvider = tagProvider;
|
||||
this.metricName = metricName;
|
||||
this.autotime = (autotime != null) ? autotime : Autotime.disabled();
|
||||
this.autoTimer = (autoTimer != null) ? autoTimer : AutoTimer.DISABLED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<ClientResponse> filter(ClientRequest clientRequest,
|
||||
ExchangeFunction exchangeFunction) {
|
||||
return exchangeFunction.exchange(clientRequest).doOnEach((signal) -> {
|
||||
if (!signal.isOnComplete() && this.autotime.isEnabled()) {
|
||||
Long startTime = signal.getContext().get(METRICS_WEBCLIENT_START_TIME);
|
||||
ClientResponse clientResponse = signal.get();
|
||||
public Mono<ClientResponse> filter(ClientRequest request, ExchangeFunction next) {
|
||||
if (!this.autoTimer.isEnabled()) {
|
||||
return next.exchange(request);
|
||||
}
|
||||
return next.exchange(request).doOnEach((signal) -> {
|
||||
if (!signal.isOnComplete()) {
|
||||
Long startTime = getStartTime(signal.getContext());
|
||||
ClientResponse response = signal.get();
|
||||
Throwable throwable = signal.getThrowable();
|
||||
Iterable<Tag> tags = this.tagProvider.tags(clientRequest, clientResponse,
|
||||
throwable);
|
||||
Timer.builder(this.metricName)
|
||||
.publishPercentiles(this.autotime.getPercentiles())
|
||||
.publishPercentileHistogram(
|
||||
this.autotime.isPercentilesHistogram())
|
||||
.tags(tags).description("Timer of WebClient operation")
|
||||
Iterable<Tag> tags = this.tagProvider.tags(request, response, throwable);
|
||||
this.autoTimer.builder(this.metricName).tags(tags)
|
||||
.description("Timer of WebClient operation")
|
||||
.register(this.meterRegistry)
|
||||
.record(System.nanoTime() - startTime, TimeUnit.NANOSECONDS);
|
||||
}
|
||||
}).subscriberContext((context) -> context.put(METRICS_WEBCLIENT_START_TIME,
|
||||
System.nanoTime()));
|
||||
}).subscriberContext(this::putStartTime);
|
||||
}
|
||||
|
||||
private Long getStartTime(Context context) {
|
||||
return context.get(METRICS_WEBCLIENT_START_TIME);
|
||||
}
|
||||
|
||||
private Context putStartTime(Context context) {
|
||||
return context.put(METRICS_WEBCLIENT_START_TIME, System.nanoTime());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,11 +20,10 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.Tag;
|
||||
import io.micrometer.core.instrument.Timer;
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.boot.actuate.metrics.Autotime;
|
||||
import org.springframework.boot.actuate.metrics.AutoTimer;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
|
@ -48,7 +47,7 @@ public class MetricsWebFilter implements WebFilter {
|
|||
|
||||
private final String metricName;
|
||||
|
||||
private final Autotime autotime;
|
||||
private final AutoTimer autoTimer;
|
||||
|
||||
/**
|
||||
* Create a new {@code MetricsWebFilter}.
|
||||
|
@ -57,13 +56,12 @@ public class MetricsWebFilter implements WebFilter {
|
|||
* @param metricName name of the metric to record
|
||||
* @param autoTimeRequests if requests should be automatically timed
|
||||
* @deprecated since 2.2.0 in favor of
|
||||
* {@link #MetricsWebFilter(MeterRegistry, WebFluxTagsProvider, String, Autotime)}
|
||||
* {@link #MetricsWebFilter(MeterRegistry, WebFluxTagsProvider, String, AutoTimer)}
|
||||
*/
|
||||
@Deprecated
|
||||
public MetricsWebFilter(MeterRegistry registry, WebFluxTagsProvider tagsProvider,
|
||||
String metricName, boolean autoTimeRequests) {
|
||||
this(registry, tagsProvider, metricName,
|
||||
new Autotime(autoTimeRequests, false, null));
|
||||
this(registry, tagsProvider, metricName, AutoTimer.ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -71,48 +69,51 @@ public class MetricsWebFilter implements WebFilter {
|
|||
* @param registry the registry to which metrics are recorded
|
||||
* @param tagsProvider provider for metrics tags
|
||||
* @param metricName name of the metric to record
|
||||
* @param autotime auto timed request settings
|
||||
* @param autoTimer the auto-timers to apply or {@code null} to disable auto-timing
|
||||
* @since 2.2.0
|
||||
*/
|
||||
public MetricsWebFilter(MeterRegistry registry, WebFluxTagsProvider tagsProvider,
|
||||
String metricName, Autotime autotime) {
|
||||
String metricName, AutoTimer autoTimer) {
|
||||
this.registry = registry;
|
||||
this.tagsProvider = tagsProvider;
|
||||
this.metricName = metricName;
|
||||
this.autotime = (autotime != null) ? autotime : Autotime.disabled();
|
||||
this.autoTimer = (autoTimer != null) ? autoTimer : AutoTimer.DISABLED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
|
||||
if (this.autotime.isEnabled()) {
|
||||
return chain.filter(exchange).compose((call) -> filter(exchange, call));
|
||||
if (!this.autoTimer.isEnabled()) {
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
return chain.filter(exchange);
|
||||
return chain.filter(exchange).compose((call) -> filter(exchange, call));
|
||||
}
|
||||
|
||||
private Publisher<Void> filter(ServerWebExchange exchange, Mono<Void> call) {
|
||||
long start = System.nanoTime();
|
||||
return call.doOnSuccess((done) -> onSuccess(exchange, start))
|
||||
.doOnError((cause) -> onError(exchange, start, cause));
|
||||
}
|
||||
|
||||
private void onSuccess(ServerWebExchange exchange, long start) {
|
||||
record(exchange, start, null);
|
||||
}
|
||||
|
||||
private void onError(ServerWebExchange exchange, long start, Throwable cause) {
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
return call.doOnSuccess((done) -> record(exchange, start, null))
|
||||
.doOnError((cause) -> {
|
||||
if (response.isCommitted()) {
|
||||
record(exchange, start, cause);
|
||||
}
|
||||
else {
|
||||
response.beforeCommit(() -> {
|
||||
record(exchange, start, cause);
|
||||
return Mono.empty();
|
||||
});
|
||||
}
|
||||
});
|
||||
if (response.isCommitted()) {
|
||||
record(exchange, start, cause);
|
||||
}
|
||||
else {
|
||||
response.beforeCommit(() -> {
|
||||
record(exchange, start, cause);
|
||||
return Mono.empty();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void record(ServerWebExchange exchange, long start, Throwable cause) {
|
||||
Iterable<Tag> tags = this.tagsProvider.httpRequestTags(exchange, cause);
|
||||
Timer.builder(this.metricName).tags(tags)
|
||||
.publishPercentiles(this.autotime.getPercentiles())
|
||||
.publishPercentileHistogram(this.autotime.isPercentilesHistogram())
|
||||
.register(this.registry)
|
||||
this.autoTimer.builder(this.metricName).tags(tags).register(this.registry)
|
||||
.record(System.nanoTime() - start, TimeUnit.NANOSECONDS);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ import java.io.IOException;
|
|||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
|
@ -29,12 +28,11 @@ import javax.servlet.http.HttpServletResponse;
|
|||
|
||||
import io.micrometer.core.annotation.Timed;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.Tag;
|
||||
import io.micrometer.core.instrument.Timer;
|
||||
import io.micrometer.core.instrument.Timer.Builder;
|
||||
import io.micrometer.core.instrument.Timer.Sample;
|
||||
|
||||
import org.springframework.boot.actuate.metrics.Autotime;
|
||||
import org.springframework.boot.actuate.metrics.AutoTimer;
|
||||
import org.springframework.core.annotation.MergedAnnotationCollectors;
|
||||
import org.springframework.core.annotation.MergedAnnotations;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
@ -60,7 +58,7 @@ public class WebMvcMetricsFilter extends OncePerRequestFilter {
|
|||
|
||||
private final String metricName;
|
||||
|
||||
private final Autotime autotime;
|
||||
private final AutoTimer autoTimer;
|
||||
|
||||
/**
|
||||
* Create a new {@link WebMvcMetricsFilter} instance.
|
||||
|
@ -70,13 +68,12 @@ public class WebMvcMetricsFilter extends OncePerRequestFilter {
|
|||
* @param autoTimeRequests if requests should be automatically timed
|
||||
* @since 2.0.7
|
||||
* @deprecated since 2.2.0 in favor of
|
||||
* {@link #WebMvcMetricsFilter(MeterRegistry, WebMvcTagsProvider, String, Autotime)}
|
||||
* {@link #WebMvcMetricsFilter(MeterRegistry, WebMvcTagsProvider, String, AutoTimer)}
|
||||
*/
|
||||
@Deprecated
|
||||
public WebMvcMetricsFilter(MeterRegistry registry, WebMvcTagsProvider tagsProvider,
|
||||
String metricName, boolean autoTimeRequests) {
|
||||
this(registry, tagsProvider, metricName,
|
||||
new Autotime(autoTimeRequests, false, null));
|
||||
this(registry, tagsProvider, metricName, AutoTimer.ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -84,15 +81,15 @@ public class WebMvcMetricsFilter extends OncePerRequestFilter {
|
|||
* @param registry the meter registry
|
||||
* @param tagsProvider the tags provider
|
||||
* @param metricName the metric name
|
||||
* @param autotime auto timed request settings
|
||||
* @param autoTimer the auto-timers to apply or {@code null} to disable auto-timing
|
||||
* @since 2.2.0
|
||||
*/
|
||||
public WebMvcMetricsFilter(MeterRegistry registry, WebMvcTagsProvider tagsProvider,
|
||||
String metricName, Autotime autotime) {
|
||||
String metricName, AutoTimer autoTimer) {
|
||||
this.registry = registry;
|
||||
this.tagsProvider = tagsProvider;
|
||||
this.metricName = metricName;
|
||||
this.autotime = autotime;
|
||||
this.autoTimer = autoTimer;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -104,12 +101,6 @@ public class WebMvcMetricsFilter extends OncePerRequestFilter {
|
|||
protected void doFilterInternal(HttpServletRequest request,
|
||||
HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
filterAndRecordMetrics(request, response, filterChain);
|
||||
}
|
||||
|
||||
private void filterAndRecordMetrics(HttpServletRequest request,
|
||||
HttpServletResponse response, FilterChain filterChain)
|
||||
throws IOException, ServletException {
|
||||
TimingContext timingContext = TimingContext.get(request);
|
||||
if (timingContext == null) {
|
||||
timingContext = startAndAttachTimingContext(request);
|
||||
|
@ -123,16 +114,16 @@ public class WebMvcMetricsFilter extends OncePerRequestFilter {
|
|||
// TimingContext that was attached to the first)
|
||||
Throwable exception = (Throwable) request
|
||||
.getAttribute(DispatcherServlet.EXCEPTION_ATTRIBUTE);
|
||||
record(timingContext, response, request, exception);
|
||||
record(timingContext, request, response, exception);
|
||||
}
|
||||
}
|
||||
catch (NestedServletException ex) {
|
||||
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
|
||||
record(timingContext, response, request, ex.getCause());
|
||||
record(timingContext, request, response, ex.getCause());
|
||||
throw ex;
|
||||
}
|
||||
catch (ServletException | IOException | RuntimeException ex) {
|
||||
record(timingContext, response, request, ex);
|
||||
record(timingContext, request, response, ex);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
@ -144,6 +135,26 @@ public class WebMvcMetricsFilter extends OncePerRequestFilter {
|
|||
return timingContext;
|
||||
}
|
||||
|
||||
private void record(TimingContext timingContext, HttpServletRequest request,
|
||||
HttpServletResponse response, Throwable exception) {
|
||||
Object handler = getHandler(request);
|
||||
Set<Timed> annotations = getTimedAnnotations(handler);
|
||||
Timer.Sample timerSample = timingContext.getTimerSample();
|
||||
if (annotations.isEmpty()) {
|
||||
Builder builder = this.autoTimer.builder(this.metricName);
|
||||
timerSample.stop(getTimer(builder, handler, request, response, exception));
|
||||
return;
|
||||
}
|
||||
for (Timed annotation : annotations) {
|
||||
Builder builder = Timer.builder(annotation, this.metricName);
|
||||
timerSample.stop(getTimer(builder, handler, request, response, exception));
|
||||
}
|
||||
}
|
||||
|
||||
private Object getHandler(HttpServletRequest request) {
|
||||
return request.getAttribute(HandlerMapping.BEST_MATCHING_HANDLER_ATTRIBUTE);
|
||||
}
|
||||
|
||||
private Set<Timed> getTimedAnnotations(Object handler) {
|
||||
if (!(handler instanceof HandlerMethod)) {
|
||||
return Collections.emptySet();
|
||||
|
@ -152,45 +163,27 @@ public class WebMvcMetricsFilter extends OncePerRequestFilter {
|
|||
}
|
||||
|
||||
private Set<Timed> getTimedAnnotations(HandlerMethod handler) {
|
||||
Set<Timed> timed = findTimedAnnotations(handler.getMethod());
|
||||
if (timed.isEmpty()) {
|
||||
return findTimedAnnotations(handler.getBeanType());
|
||||
Set<Timed> methodAnnotations = findTimedAnnotations(handler.getMethod());
|
||||
if (!methodAnnotations.isEmpty()) {
|
||||
return methodAnnotations;
|
||||
}
|
||||
return timed;
|
||||
return findTimedAnnotations(handler.getBeanType());
|
||||
}
|
||||
|
||||
private Set<Timed> findTimedAnnotations(AnnotatedElement element) {
|
||||
return MergedAnnotations.from(element).stream(Timed.class)
|
||||
MergedAnnotations annotations = MergedAnnotations.from(element);
|
||||
if (!annotations.isPresent(Timed.class)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
return annotations.stream(Timed.class)
|
||||
.collect(MergedAnnotationCollectors.toAnnotationSet());
|
||||
}
|
||||
|
||||
private void record(TimingContext timingContext, HttpServletResponse response,
|
||||
HttpServletRequest request, Throwable exception) {
|
||||
Object handlerObject = request
|
||||
.getAttribute(HandlerMapping.BEST_MATCHING_HANDLER_ATTRIBUTE);
|
||||
Set<Timed> annotations = getTimedAnnotations(handlerObject);
|
||||
Timer.Sample timerSample = timingContext.getTimerSample();
|
||||
Supplier<Iterable<Tag>> tags = () -> this.tagsProvider.getTags(request, response,
|
||||
handlerObject, exception);
|
||||
if (annotations.isEmpty()) {
|
||||
if (this.autotime.isEnabled()) {
|
||||
stop(timerSample, tags,
|
||||
Timer.builder(this.metricName)
|
||||
.publishPercentiles(this.autotime.getPercentiles())
|
||||
.publishPercentileHistogram(
|
||||
this.autotime.isPercentilesHistogram()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (Timed annotation : annotations) {
|
||||
stop(timerSample, tags, Timer.builder(annotation, this.metricName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void stop(Timer.Sample timerSample, Supplier<Iterable<Tag>> tags,
|
||||
Builder builder) {
|
||||
timerSample.stop(builder.tags(tags.get()).register(this.registry));
|
||||
private Timer getTimer(Builder builder, Object handler, HttpServletRequest request,
|
||||
HttpServletResponse response, Throwable exception) {
|
||||
return builder
|
||||
.tags(this.tagsProvider.getTags(request, response, handler, exception))
|
||||
.register(this.registry);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -27,7 +27,7 @@ import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
|
|||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.metrics.Autotime;
|
||||
import org.springframework.boot.actuate.metrics.AutoTimer;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.client.MockRestServiceServer;
|
||||
|
@ -60,7 +60,7 @@ public class MetricsRestTemplateCustomizerTests {
|
|||
this.mockServer = MockRestServiceServer.createServer(this.restTemplate);
|
||||
this.customizer = new MetricsRestTemplateCustomizer(this.registry,
|
||||
new DefaultRestTemplateExchangeTagsProvider(), "http.client.requests",
|
||||
new Autotime());
|
||||
AutoTimer.ENABLED);
|
||||
this.customizer.customize(this.restTemplate);
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ import org.junit.jupiter.api.BeforeEach;
|
|||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.boot.actuate.metrics.Autotime;
|
||||
import org.springframework.boot.actuate.metrics.AutoTimer;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.reactive.function.client.ClientRequest;
|
||||
|
@ -65,7 +65,7 @@ public class MetricsWebClientFilterFunctionTests {
|
|||
this.registry = new SimpleMeterRegistry(SimpleConfig.DEFAULT, new MockClock());
|
||||
this.filterFunction = new MetricsWebClientFilterFunction(this.registry,
|
||||
new DefaultWebClientExchangeTagsProvider(), "http.client.requests",
|
||||
new Autotime());
|
||||
AutoTimer.ENABLED);
|
||||
this.response = mock(ClientResponse.class);
|
||||
this.exchange = (r) -> Mono.just(this.response);
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ import org.junit.jupiter.api.BeforeEach;
|
|||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.boot.actuate.metrics.Autotime;
|
||||
import org.springframework.boot.actuate.metrics.AutoTimer;
|
||||
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
|
||||
import org.springframework.mock.web.server.MockServerWebExchange;
|
||||
import org.springframework.web.reactive.HandlerMapping;
|
||||
|
@ -51,7 +51,8 @@ public class MetricsWebFilterTests {
|
|||
MockClock clock = new MockClock();
|
||||
this.registry = new SimpleMeterRegistry(SimpleConfig.DEFAULT, clock);
|
||||
this.webFilter = new MetricsWebFilter(this.registry,
|
||||
new DefaultWebFluxTagsProvider(), REQUEST_METRICS_NAME, new Autotime());
|
||||
new DefaultWebFluxTagsProvider(), REQUEST_METRICS_NAME,
|
||||
AutoTimer.ENABLED);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
|
||||
package org.springframework.boot.actuate.metrics.web.servlet;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import io.micrometer.core.instrument.Clock;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.MockClock;
|
||||
|
@ -30,7 +28,6 @@ import org.junit.jupiter.api.Test;
|
|||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.metrics.Autotime;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
@ -108,7 +105,8 @@ public class WebMvcMetricsFilterAutoTimedTests {
|
|||
MeterRegistry registry) {
|
||||
return new WebMvcMetricsFilter(registry, new DefaultWebMvcTagsProvider(),
|
||||
"http.server.requests",
|
||||
new Autotime(true, true, Arrays.asList(0.5, 0.95)));
|
||||
(builder) -> builder.publishPercentiles(0.5, 0.95)
|
||||
.publishPercentileHistogram(true));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
|||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.actuate.metrics.Autotime;
|
||||
import org.springframework.boot.actuate.metrics.AutoTimer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
@ -373,7 +373,7 @@ public class WebMvcMetricsFilterTests {
|
|||
WebMvcMetricsFilter webMetricsFilter(MeterRegistry registry,
|
||||
WebApplicationContext ctx) {
|
||||
return new WebMvcMetricsFilter(registry, new DefaultWebMvcTagsProvider(),
|
||||
"http.server.requests", new Autotime());
|
||||
"http.server.requests", AutoTimer.ENABLED);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ import org.junit.jupiter.api.Test;
|
|||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.metrics.Autotime;
|
||||
import org.springframework.boot.actuate.metrics.AutoTimer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
@ -112,7 +112,7 @@ public class WebMvcMetricsIntegrationTests {
|
|||
public WebMvcMetricsFilter webMetricsFilter(MeterRegistry registry,
|
||||
WebApplicationContext ctx) {
|
||||
return new WebMvcMetricsFilter(registry, new DefaultWebMvcTagsProvider(),
|
||||
"http.server.requests", new Autotime());
|
||||
"http.server.requests", AutoTimer.ENABLED);
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
|
|
Loading…
Reference in New Issue