Skip to content

Commit 68a3fbd

Browse files
committed
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
1 parent ad5e905 commit 68a3fbd

File tree

15 files changed

+264
-177
lines changed

15 files changed

+264
-177
lines changed

spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/Autotime.java renamed to spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/AutoTimeProperties.java

Lines changed: 13 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,21 @@
1414
* limitations under the License.
1515
*/
1616

17-
package org.springframework.boot.actuate.metrics;
17+
package org.springframework.boot.actuate.autoconfigure.metrics;
1818

19-
import java.util.List;
19+
import io.micrometer.core.instrument.Timer.Builder;
20+
21+
import org.springframework.boot.actuate.metrics.AutoTimer;
2022

2123
/**
22-
* Settings for requests that are automatically timed.
24+
* Nested configuration properties for items that are automatically timed.
2325
*
2426
* @author Tadaya Tsuyukubo
2527
* @author Stephane Nicoll
28+
* @author Phillip Webb
2629
* @since 2.2.0
2730
*/
28-
public final class Autotime {
31+
public final class AutoTimeProperties implements AutoTimer {
2932

3033
private boolean enabled = true;
3134

@@ -36,24 +39,10 @@ public final class Autotime {
3639
/**
3740
* Create an instance that automatically time requests with no percentiles.
3841
*/
39-
public Autotime() {
40-
}
41-
42-
/**
43-
* Create an instance with the specified settings.
44-
* @param enabled whether requests should be automatically timed
45-
* @param percentilesHistogram whether percentile histograms should be published
46-
* @param percentiles computed non-aggregable percentiles to publish (can be
47-
* {@code null})
48-
*/
49-
public Autotime(boolean enabled, boolean percentilesHistogram,
50-
List<Double> percentiles) {
51-
this.enabled = enabled;
52-
this.percentilesHistogram = percentilesHistogram;
53-
this.percentiles = (percentiles != null)
54-
? percentiles.stream().mapToDouble(Double::doubleValue).toArray() : null;
42+
public AutoTimeProperties() {
5543
}
5644

45+
@Override
5746
public boolean isEnabled() {
5847
return this.enabled;
5948
}
@@ -78,12 +67,10 @@ public void setPercentiles(double[] percentiles) {
7867
this.percentiles = percentiles;
7968
}
8069

81-
/**
82-
* Create an instance that disable auto-timed requests.
83-
* @return an instance that disable auto-timed requests
84-
*/
85-
public static Autotime disabled() {
86-
return new Autotime(false, false, null);
70+
@Override
71+
public void apply(Builder builder) {
72+
builder.publishPercentileHistogram(this.percentilesHistogram)
73+
.publishPercentiles(this.percentiles);
8774
}
8875

8976
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsProperties.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import java.util.LinkedHashMap;
2020
import java.util.Map;
2121

22-
import org.springframework.boot.actuate.metrics.Autotime;
2322
import org.springframework.boot.context.properties.ConfigurationProperties;
2423
import org.springframework.boot.context.properties.DeprecatedConfigurationProperty;
2524
import org.springframework.boot.context.properties.NestedConfigurationProperty;
@@ -116,6 +115,7 @@ public ClientRequest getRequest() {
116115
* @return request metric name
117116
* @deprecated since 2.2.0 in favor of {@link ClientRequest#getMetricName()}
118117
*/
118+
@Deprecated
119119
@DeprecatedConfigurationProperty(
120120
replacement = "management.metrics.web.client.request.metric-name")
121121
public String getRequestsMetricName() {
@@ -128,6 +128,7 @@ public String getRequestsMetricName() {
128128
* @deprecated since 2.2.0 in favor of
129129
* {@link ClientRequest#setMetricName(String)}
130130
*/
131+
@Deprecated
131132
public void setRequestsMetricName(String requestsMetricName) {
132133
this.request.setMetricName(requestsMetricName);
133134
}
@@ -151,10 +152,10 @@ public static class ClientRequest {
151152
* Auto-timed request settings.
152153
*/
153154
@NestedConfigurationProperty
154-
private final Autotime autoTime = new Autotime();
155+
private final AutoTimeProperties autotime = new AutoTimeProperties();
155156

156-
public Autotime getAutotime() {
157-
return this.autoTime;
157+
public AutoTimeProperties getAutotime() {
158+
return this.autotime;
158159
}
159160

160161
public String getMetricName() {
@@ -187,7 +188,7 @@ public ServerRequest getRequest() {
187188
/**
188189
* Return whether server requests should be automatically timed.
189190
* @return {@code true} if server request should be automatically timed
190-
* @deprecated since 2.2.0 in favor of {@link Autotime#isEnabled()}
191+
* @deprecated since 2.2.0 in favor of {@link AutoTimeProperties#isEnabled()}
191192
*/
192193
@DeprecatedConfigurationProperty(
193194
replacement = "management.metrics.web.server.request.autotime.enabled")
@@ -200,7 +201,7 @@ public boolean isAutoTimeRequests() {
200201
* Set whether server requests should be automatically timed.
201202
* @param autoTimeRequests whether server requests should be automatically
202203
* timed
203-
* @deprecated since 2.2.0 in favor of {@link Autotime#isEnabled()}
204+
* @deprecated since 2.2.0 in favor of {@link AutoTimeProperties#isEnabled()}
204205
*/
205206
@Deprecated
206207
public void setAutoTimeRequests(boolean autoTimeRequests) {
@@ -249,9 +250,9 @@ public static class ServerRequest {
249250
* Auto-timed request settings.
250251
*/
251252
@NestedConfigurationProperty
252-
private final Autotime autotime = new Autotime();
253+
private final AutoTimeProperties autotime = new AutoTimeProperties();
253254

254-
public Autotime getAutotime() {
255+
public AutoTimeProperties getAutotime() {
255256
return this.autotime;
256257
}
257258

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* Copyright 2012-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.metrics;
18+
/**
19+
* @author pwebb
20+
*/
21+
22+
import java.util.function.Supplier;
23+
24+
import io.micrometer.core.annotation.Timed;
25+
import io.micrometer.core.instrument.Timer;
26+
import io.micrometer.core.instrument.Timer.Builder;
27+
28+
/**
29+
* Strategy that can be used to apply {@link Timer Timers} automatically instead of using
30+
* {@link Timed @Timed}.
31+
*
32+
* @author Tadaya Tsuyukubo
33+
* @author Stephane Nicoll
34+
* @author Phillip Webb
35+
* @since 2.2.0
36+
*/
37+
@FunctionalInterface
38+
public interface AutoTimer {
39+
40+
/**
41+
* An {@link AutoTimer} implementation that is enabled but applies no additional
42+
* customizations.
43+
*/
44+
AutoTimer ENABLED = (builder) -> {
45+
};
46+
47+
/**
48+
* An {@link AutoTimer} implementation that is disabled and will not record metrics.
49+
*/
50+
AutoTimer DISABLED = new AutoTimer() {
51+
52+
@Override
53+
public boolean isEnabled() {
54+
return false;
55+
}
56+
57+
@Override
58+
public void apply(Builder builder) {
59+
throw new IllegalStateException("AutoTimer is disabled");
60+
}
61+
62+
};
63+
64+
/**
65+
* Return if the auto-timer is enabled and metrics should be recorded.
66+
* @return if the auto-timer is enabled
67+
*/
68+
default boolean isEnabled() {
69+
return true;
70+
}
71+
72+
/**
73+
* Factory method to create a new {@link Builder Timer.Builder} with auto-timer
74+
* settings {@link #apply(Builder) applied}.
75+
* @param name the name of the timer
76+
* @return a new builder instance with auto-settings applied
77+
*/
78+
default Timer.Builder builder(String name) {
79+
return builder(() -> Timer.builder(name));
80+
}
81+
82+
/**
83+
* Factory method to create a new {@link Builder Timer.Builder} with auto-timer
84+
* settings {@link #apply(Builder) applied}.
85+
* @param supplier the builder supplier
86+
* @return a new builder instance with auto-settings applied
87+
*/
88+
default Timer.Builder builder(Supplier<Timer.Builder> supplier) {
89+
Timer.Builder builder = supplier.get();
90+
apply(builder);
91+
return builder;
92+
}
93+
94+
/**
95+
* Called to apply any auto-timer settings to the given {@link Builder Timer.Builder}.
96+
* @param builder the builder to apply settings to
97+
*/
98+
void apply(Timer.Builder builder);
99+
100+
}

spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/client/MetricsClientHttpRequestInterceptor.java

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
import io.micrometer.core.instrument.MeterRegistry;
2525
import io.micrometer.core.instrument.Timer;
2626

27-
import org.springframework.boot.actuate.metrics.Autotime;
27+
import org.springframework.boot.actuate.metrics.AutoTimer;
2828
import org.springframework.core.NamedThreadLocal;
2929
import org.springframework.http.HttpRequest;
3030
import org.springframework.http.client.ClientHttpRequestExecution;
@@ -51,52 +51,54 @@ class MetricsClientHttpRequestInterceptor implements ClientHttpRequestIntercepto
5151

5252
private final String metricName;
5353

54-
private final Autotime autotime;
54+
private final AutoTimer autoTimer;
5555

5656
/**
5757
* Create a new {@code MetricsClientHttpRequestInterceptor}.
5858
* @param meterRegistry the registry to which metrics are recorded
5959
* @param tagProvider provider for metrics tags
6060
* @param metricName name of the metric to record
6161
* @deprecated since 2.2.0 in favor of
62-
* {@link #MetricsClientHttpRequestInterceptor(MeterRegistry, RestTemplateExchangeTagsProvider, String, Autotime)}
62+
* {@link #MetricsClientHttpRequestInterceptor(MeterRegistry, RestTemplateExchangeTagsProvider, String, AutoTimer)}
6363
*/
64+
@Deprecated
6465
MetricsClientHttpRequestInterceptor(MeterRegistry meterRegistry,
6566
RestTemplateExchangeTagsProvider tagProvider, String metricName) {
66-
this(meterRegistry, tagProvider, metricName, new Autotime());
67+
this(meterRegistry, tagProvider, metricName, AutoTimer.ENABLED);
6768
}
6869

6970
/**
7071
* Create a new {@code MetricsClientHttpRequestInterceptor}.
7172
* @param meterRegistry the registry to which metrics are recorded
7273
* @param tagProvider provider for metrics tags
7374
* @param metricName name of the metric to record
74-
* @param autotime auto timed request settings
75+
* @param autoTimer the auto-timers to apply or {@code null} to disable auto-timing
7576
* @since 2.2.0
7677
*/
7778
MetricsClientHttpRequestInterceptor(MeterRegistry meterRegistry,
7879
RestTemplateExchangeTagsProvider tagProvider, String metricName,
79-
Autotime autotime) {
80+
AutoTimer autoTimer) {
8081
this.tagProvider = tagProvider;
8182
this.meterRegistry = meterRegistry;
8283
this.metricName = metricName;
83-
this.autotime = (autotime != null) ? autotime : Autotime.disabled();
84+
this.autoTimer = (autoTimer != null) ? autoTimer : AutoTimer.DISABLED;
8485
}
8586

8687
@Override
8788
public ClientHttpResponse intercept(HttpRequest request, byte[] body,
8889
ClientHttpRequestExecution execution) throws IOException {
90+
if (!this.autoTimer.isEnabled()) {
91+
return execution.execute(request, body);
92+
}
8993
long startTime = System.nanoTime();
9094
ClientHttpResponse response = null;
9195
try {
9296
response = execution.execute(request, body);
9397
return response;
9498
}
9599
finally {
96-
if (this.autotime.isEnabled()) {
97-
getTimeBuilder(request, response).register(this.meterRegistry)
98-
.record(System.nanoTime() - startTime, TimeUnit.NANOSECONDS);
99-
}
100+
getTimeBuilder(request, response).register(this.meterRegistry)
101+
.record(System.nanoTime() - startTime, TimeUnit.NANOSECONDS);
100102
urlTemplate.remove();
101103
}
102104
}
@@ -121,9 +123,7 @@ public URI expand(String url, Object... arguments) {
121123

122124
private Timer.Builder getTimeBuilder(HttpRequest request,
123125
ClientHttpResponse response) {
124-
return Timer.builder(this.metricName)
125-
.publishPercentiles(this.autotime.getPercentiles())
126-
.publishPercentileHistogram(this.autotime.isPercentilesHistogram())
126+
return this.autoTimer.builder(this.metricName)
127127
.tags(this.tagProvider.getTags(urlTemplate.get(), request, response))
128128
.description("Timer of RestTemplate operation");
129129
}

spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/client/MetricsRestTemplateCustomizer.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
import io.micrometer.core.instrument.MeterRegistry;
2323

24-
import org.springframework.boot.actuate.metrics.Autotime;
24+
import org.springframework.boot.actuate.metrics.AutoTimer;
2525
import org.springframework.boot.web.client.RestTemplateCustomizer;
2626
import org.springframework.http.client.ClientHttpRequestInterceptor;
2727
import org.springframework.web.client.RestTemplate;
@@ -47,29 +47,30 @@ public class MetricsRestTemplateCustomizer implements RestTemplateCustomizer {
4747
* @param tagProvider the tag provider
4848
* @param metricName the name of the recorded metric
4949
* @deprecated since 2.2.0 in favor of
50-
* {@link #MetricsRestTemplateCustomizer(MeterRegistry, RestTemplateExchangeTagsProvider, String, Autotime)}
50+
* {@link #MetricsRestTemplateCustomizer(MeterRegistry, RestTemplateExchangeTagsProvider, String, AutoTimer)}
5151
*/
52+
@Deprecated
5253
public MetricsRestTemplateCustomizer(MeterRegistry meterRegistry,
5354
RestTemplateExchangeTagsProvider tagProvider, String metricName) {
54-
this(meterRegistry, tagProvider, metricName, new Autotime());
55+
this(meterRegistry, tagProvider, metricName, AutoTimer.ENABLED);
5556
}
5657

5758
/**
5859
* Creates a new {@code MetricsRestTemplateInterceptor}. When {@code autoTimeRequests}
5960
* is set to {@code true}, the interceptor records metrics using the given
6061
* {@code meterRegistry} with tags provided by the given {@code tagProvider} and with
61-
* {@link Autotime auto-timed request configuration}.
62+
* {@link AutoTimer auto-timed configuration}.
6263
* @param meterRegistry the meter registry
6364
* @param tagProvider the tag provider
6465
* @param metricName the name of the recorded metric
65-
* @param autotime auto-timed request settings
66+
* @param autoTimer the auto-timers to apply or {@code null} to disable auto-timing
6667
* @since 2.2.0
6768
*/
6869
public MetricsRestTemplateCustomizer(MeterRegistry meterRegistry,
6970
RestTemplateExchangeTagsProvider tagProvider, String metricName,
70-
Autotime autotime) {
71+
AutoTimer autoTimer) {
7172
this.interceptor = new MetricsClientHttpRequestInterceptor(meterRegistry,
72-
tagProvider, metricName, autotime);
73+
tagProvider, metricName, autoTimer);
7374
}
7475

7576
@Override

0 commit comments

Comments
 (0)