Skip to content

Commit 96712be

Browse files
committed
Add properties for default config of auto-timed controller metrics
When `management.metrics.web.server.autoTimeRequests` is enabled (default=true), spring-boot collects metrics on controller methods even when they are not annotated with `@Timed`. When this happens, created metrics are based on the default configuration values of `@Timed`. Currently, there is no way to specify the default configuration to those auto-timed controller metrics. This commit introduces two properties: - `management.metrics.web.server.autoTimeRequestsDefaultPercentiles` - `management.metrics.web.server.autoTimeRequestsDefaultHistogram` When values are set to the above properties, they will be applied to auto-timed controller metrics.
1 parent 9540905 commit 96712be

File tree

10 files changed

+167
-31
lines changed

10 files changed

+167
-31
lines changed

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

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

22+
import io.micrometer.core.annotation.Timed;
23+
2224
import org.springframework.boot.context.properties.ConfigurationProperties;
2325

2426
/**
@@ -133,6 +135,20 @@ public static class Server {
133135
*/
134136
private boolean autoTimeRequests = true;
135137

138+
/**
139+
* Default percentiles when "autoTimeRequests=true" and @Timed annotation is
140+
* not presented on the corresponding request handler. Any @Timed annotation
141+
* presented will have precedence.
142+
*/
143+
private double[] autoTimeRequestsDefaultPercentiles;
144+
145+
/**
146+
* Default histogram when "autoTimeRequests=true" and @Timed annotation is not
147+
* presented on the corresponding request handler. Any @Timed annotation
148+
* presented will have precedence.
149+
*/
150+
private boolean autoTimeRequestsDefaultHistogram;
151+
136152
/**
137153
* Name of the metric for received requests.
138154
*/
@@ -153,6 +169,24 @@ public void setAutoTimeRequests(boolean autoTimeRequests) {
153169
this.autoTimeRequests = autoTimeRequests;
154170
}
155171

172+
public double[] getAutoTimeRequestsDefaultPercentiles() {
173+
return this.autoTimeRequestsDefaultPercentiles;
174+
}
175+
176+
public void setAutoTimeRequestsDefaultPercentiles(
177+
double[] autoTimeRequestsDefaultPercentiles) {
178+
this.autoTimeRequestsDefaultPercentiles = autoTimeRequestsDefaultPercentiles;
179+
}
180+
181+
public boolean isAutoTimeRequestsDefaultHistogram() {
182+
return this.autoTimeRequestsDefaultHistogram;
183+
}
184+
185+
public void setAutoTimeRequestsDefaultHistogram(
186+
boolean autoTimeRequestsDefaultHistogram) {
187+
this.autoTimeRequestsDefaultHistogram = autoTimeRequestsDefaultHistogram;
188+
}
189+
156190
public String getRequestsMetricName() {
157191
return this.requestsMetricName;
158192
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebFluxMetricsAutoConfiguration.java

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

2222
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
2323
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties;
24+
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties.Web.Server;
2425
import org.springframework.boot.actuate.autoconfigure.metrics.OnlyOnceLoggingDenyMeterFilter;
2526
import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration;
2627
import org.springframework.boot.actuate.metrics.web.reactive.server.DefaultWebFluxTagsProvider;
@@ -65,9 +66,12 @@ public DefaultWebFluxTagsProvider webfluxTagConfigurer() {
6566
@Bean
6667
public MetricsWebFilter webfluxMetrics(MeterRegistry registry,
6768
WebFluxTagsProvider tagConfigurer) {
69+
Server serverProperties = this.properties.getWeb().getServer();
6870
return new MetricsWebFilter(registry, tagConfigurer,
69-
this.properties.getWeb().getServer().getRequestsMetricName(),
70-
this.properties.getWeb().getServer().isAutoTimeRequests());
71+
serverProperties.getRequestsMetricName(),
72+
serverProperties.isAutoTimeRequests(),
73+
serverProperties.getAutoTimeRequestsDefaultPercentiles(),
74+
serverProperties.isAutoTimeRequestsDefaultHistogram());
7175
}
7276

7377
@Bean

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/servlet/WebMvcMetricsAutoConfiguration.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,9 @@ public FilterRegistrationBean<WebMvcMetricsFilter> webMvcMetricsFilter(
8181
Server serverProperties = this.properties.getWeb().getServer();
8282
WebMvcMetricsFilter filter = new WebMvcMetricsFilter(registry, tagsProvider,
8383
serverProperties.getRequestsMetricName(),
84-
serverProperties.isAutoTimeRequests());
84+
serverProperties.isAutoTimeRequests(),
85+
serverProperties.getAutoTimeRequestsDefaultPercentiles(),
86+
serverProperties.isAutoTimeRequestsDefaultHistogram());
8587
FilterRegistrationBean<WebMvcMetricsFilter> registration = new FilterRegistrationBean<>(
8688
filter);
8789
registration.setOrder(Ordered.HIGHEST_PRECEDENCE + 1);

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/servlet/WebMvcMetricsAutoConfigurationTests.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626

2727
import io.micrometer.core.instrument.MeterRegistry;
2828
import io.micrometer.core.instrument.Tag;
29+
import io.micrometer.core.instrument.Timer;
30+
import io.micrometer.core.instrument.distribution.HistogramSnapshot;
2931
import org.junit.Rule;
3032
import org.junit.Test;
3133

@@ -137,6 +139,26 @@ public void shouldNotDenyNorLogIfMaxUrisIsNotReached() {
137139
});
138140
}
139141

142+
@Test
143+
public void autoTimeRequestsDefaultValues() {
144+
this.contextRunner.withUserConfiguration(TestController.class)
145+
.withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class,
146+
WebMvcAutoConfiguration.class))
147+
.withPropertyValues(
148+
"management.metrics.web.server.autoTimeRequestsDefaultPercentiles=0.5,0.7",
149+
"management.metrics.web.server.autoTimeRequestsDefaultHistogram=true")
150+
.run((context) -> {
151+
MeterRegistry registry = getInitializedMeterRegistry(context);
152+
Timer timer = registry.get("http.server.requests").timer();
153+
HistogramSnapshot snapshot = timer.takeSnapshot();
154+
assertThat(snapshot.percentileValues()).hasSize(2);
155+
assertThat(snapshot.percentileValues()[0].percentile())
156+
.isEqualTo(0.5);
157+
assertThat(snapshot.percentileValues()[1].percentile())
158+
.isEqualTo(0.7);
159+
});
160+
}
161+
140162
@Test
141163
@SuppressWarnings("rawtypes")
142164
public void longTaskTimingInterceptorIsRegistered() {

spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/MetricsWebFilter.java

Lines changed: 53 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import io.micrometer.core.instrument.MeterRegistry;
2222
import io.micrometer.core.instrument.Tag;
23+
import io.micrometer.core.instrument.Timer;
2324
import org.reactivestreams.Publisher;
2425
import reactor.core.publisher.Mono;
2526

@@ -48,26 +49,60 @@ public class MetricsWebFilter implements WebFilter {
4849

4950
private final boolean autoTimeRequests;
5051

52+
private final double[] autoTimeRequestsDefaultPercentiles;
53+
54+
private final boolean autoTimeRequestsDefaultHistogram;
55+
5156
/**
5257
* Create a new {@code MetricsWebFilter}.
5358
* @param registry the registry to which metrics are recorded
5459
* @param tagsProvider provider for metrics tags
5560
* @param metricName name of the metric to record
5661
* @deprecated since 2.0.6 in favor of
57-
* {@link #MetricsWebFilter(MeterRegistry, WebFluxTagsProvider, String, boolean)}
62+
* {@link #MetricsWebFilter(MeterRegistry, WebFluxTagsProvider, String, boolean, double[], boolean)}
5863
*/
5964
@Deprecated
6065
public MetricsWebFilter(MeterRegistry registry, WebFluxTagsProvider tagsProvider,
6166
String metricName) {
6267
this(registry, tagsProvider, metricName, true);
6368
}
6469

70+
/**
71+
* Create a new {@code MetricsWebFilter}.
72+
* @param registry the registry to which metrics are recorded
73+
* @param tagsProvider provider for metrics tags
74+
* @param metricName name of the metric to record
75+
* @param autoTimeRequests if requests should be automatically timed
76+
* @deprecated since 2.1.4 in favor of
77+
* {@link #MetricsWebFilter(MeterRegistry, WebFluxTagsProvider, String, boolean, double[], boolean)}
78+
*/
79+
@Deprecated
6580
public MetricsWebFilter(MeterRegistry registry, WebFluxTagsProvider tagsProvider,
6681
String metricName, boolean autoTimeRequests) {
82+
this(registry, tagsProvider, metricName, autoTimeRequests, null, false);
83+
}
84+
85+
/**
86+
* Create a new {@code MetricsWebFilter}.
87+
* @param registry the registry to which metrics are recorded
88+
* @param tagsProvider provider for metrics tags
89+
* @param metricName name of the metric to record
90+
* @param autoTimeRequests if requests should be automatically timed
91+
* @param autoTimeRequestsDefaultPercentiles default percentiles for auto time
92+
* requests
93+
* @param autoTimeRequestsDefaultHistogram default histogram for auto time requests
94+
* @since 2.1.4
95+
*/
96+
public MetricsWebFilter(MeterRegistry registry, WebFluxTagsProvider tagsProvider,
97+
String metricName, boolean autoTimeRequests,
98+
double[] autoTimeRequestsDefaultPercentiles,
99+
boolean autoTimeRequestsDefaultHistogram) {
67100
this.registry = registry;
68101
this.tagsProvider = tagsProvider;
69102
this.metricName = metricName;
70103
this.autoTimeRequests = autoTimeRequests;
104+
this.autoTimeRequestsDefaultPercentiles = autoTimeRequestsDefaultPercentiles;
105+
this.autoTimeRequestsDefaultHistogram = autoTimeRequestsDefaultHistogram;
71106
}
72107

73108
@Override
@@ -81,29 +116,27 @@ public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
81116
private Publisher<Void> filter(ServerWebExchange exchange, Mono<Void> call) {
82117
long start = System.nanoTime();
83118
ServerHttpResponse response = exchange.getResponse();
84-
return call.doOnSuccess((done) -> success(exchange, start)).doOnError((cause) -> {
85-
if (response.isCommitted()) {
86-
error(exchange, start, cause);
87-
}
88-
else {
89-
response.beforeCommit(() -> {
90-
error(exchange, start, cause);
91-
return Mono.empty();
119+
return call.doOnSuccess((done) -> record(exchange, start, null))
120+
.doOnError((cause) -> {
121+
if (response.isCommitted()) {
122+
record(exchange, start, cause);
123+
}
124+
else {
125+
response.beforeCommit(() -> {
126+
record(exchange, start, cause);
127+
return Mono.empty();
128+
});
129+
}
92130
});
93-
}
94-
});
95-
}
96-
97-
private void success(ServerWebExchange exchange, long start) {
98-
Iterable<Tag> tags = this.tagsProvider.httpRequestTags(exchange, null);
99-
this.registry.timer(this.metricName, tags).record(System.nanoTime() - start,
100-
TimeUnit.NANOSECONDS);
101131
}
102132

103-
private void error(ServerWebExchange exchange, long start, Throwable cause) {
133+
private void record(ServerWebExchange exchange, long start, Throwable cause) {
104134
Iterable<Tag> tags = this.tagsProvider.httpRequestTags(exchange, cause);
105-
this.registry.timer(this.metricName, tags).record(System.nanoTime() - start,
106-
TimeUnit.NANOSECONDS);
135+
Timer.builder(this.metricName).tags(tags)
136+
.publishPercentiles(this.autoTimeRequestsDefaultPercentiles)
137+
.publishPercentileHistogram(this.autoTimeRequestsDefaultHistogram)
138+
.register(this.registry)
139+
.record(System.nanoTime() - start, TimeUnit.NANOSECONDS);
107140
}
108141

109142
}

spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetricsFilter.java

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ public class WebMvcMetricsFilter extends OncePerRequestFilter {
6161

6262
private final boolean autoTimeRequests;
6363

64+
private final double[] autoTimeRequestsDefaultPercentiles;
65+
66+
private final boolean autoTimeRequestsDefaultHistogram;
67+
6468
/**
6569
* Create a new {@link WebMvcMetricsFilter} instance.
6670
* @param context the source application context
@@ -69,7 +73,7 @@ public class WebMvcMetricsFilter extends OncePerRequestFilter {
6973
* @param metricName the metric name
7074
* @param autoTimeRequests if requests should be automatically timed
7175
* @deprecated since 2.0.7 in favor of
72-
* {@link #WebMvcMetricsFilter(MeterRegistry, WebMvcTagsProvider, String, boolean)}
76+
* {@link #WebMvcMetricsFilter(MeterRegistry, WebMvcTagsProvider, String, boolean, double[], boolean)}
7377
*/
7478
@Deprecated
7579
public WebMvcMetricsFilter(ApplicationContext context, MeterRegistry registry,
@@ -85,13 +89,37 @@ public WebMvcMetricsFilter(ApplicationContext context, MeterRegistry registry,
8589
* @param metricName the metric name
8690
* @param autoTimeRequests if requests should be automatically timed
8791
* @since 2.0.7
92+
* @deprecated since 2.1.4 in favor of
93+
* {@link #WebMvcMetricsFilter(MeterRegistry, WebMvcTagsProvider, String, boolean, double[], boolean)}
8894
*/
95+
@Deprecated
8996
public WebMvcMetricsFilter(MeterRegistry registry, WebMvcTagsProvider tagsProvider,
9097
String metricName, boolean autoTimeRequests) {
98+
this(registry, tagsProvider, metricName, autoTimeRequests, null, false);
99+
}
100+
101+
/**
102+
* Create a new {@link WebMvcMetricsFilter} instance.
103+
* @param registry the meter registry
104+
* @param tagsProvider the tags provider
105+
* @param metricName the metric name
106+
* @param autoTimeRequests if requests should be automatically timed
107+
* @param autoTimeRequestsDefaultPercentiles default percentiles if requests are auto
108+
* timed
109+
* @param autoTimeRequestsDefaultHistogram default histogram flag if requests are auto
110+
* timed
111+
* @since 2.1.4
112+
*/
113+
public WebMvcMetricsFilter(MeterRegistry registry, WebMvcTagsProvider tagsProvider,
114+
String metricName, boolean autoTimeRequests,
115+
double[] autoTimeRequestsDefaultPercentiles,
116+
boolean autoTimeRequestsDefaultHistogram) {
91117
this.registry = registry;
92118
this.tagsProvider = tagsProvider;
93119
this.metricName = metricName;
94120
this.autoTimeRequests = autoTimeRequests;
121+
this.autoTimeRequestsDefaultPercentiles = autoTimeRequestsDefaultPercentiles;
122+
this.autoTimeRequestsDefaultHistogram = autoTimeRequestsDefaultHistogram;
95123
}
96124

97125
@Override
@@ -168,7 +196,12 @@ private void record(TimingContext timingContext, HttpServletResponse response,
168196
handlerObject, exception);
169197
if (annotations.isEmpty()) {
170198
if (this.autoTimeRequests) {
171-
stop(timerSample, tags, Timer.builder(this.metricName));
199+
stop(timerSample, tags,
200+
Timer.builder(this.metricName)
201+
.publishPercentiles(
202+
this.autoTimeRequestsDefaultPercentiles)
203+
.publishPercentileHistogram(
204+
this.autoTimeRequestsDefaultHistogram));
172205
}
173206
}
174207
else {

spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/server/MetricsWebFilterTests.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ public void setup() {
5050
MockClock clock = new MockClock();
5151
this.registry = new SimpleMeterRegistry(SimpleConfig.DEFAULT, clock);
5252
this.webFilter = new MetricsWebFilter(this.registry,
53-
new DefaultWebFluxTagsProvider(), REQUEST_METRICS_NAME, true);
53+
new DefaultWebFluxTagsProvider(), REQUEST_METRICS_NAME, true, null,
54+
false);
5455
}
5556

5657
@Test

spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetricsFilterAutoTimedTests.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import io.micrometer.core.instrument.Clock;
2020
import io.micrometer.core.instrument.MeterRegistry;
2121
import io.micrometer.core.instrument.MockClock;
22+
import io.micrometer.core.instrument.Timer;
23+
import io.micrometer.core.instrument.distribution.HistogramSnapshot;
2224
import io.micrometer.core.instrument.simple.SimpleConfig;
2325
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
2426
import org.junit.Before;
@@ -73,8 +75,13 @@ public void setupMockMvc() {
7375
@Test
7476
public void metricsCanBeAutoTimed() throws Exception {
7577
this.mvc.perform(get("/api/10")).andExpect(status().isOk());
76-
assertThat(this.registry.get("http.server.requests").tags("status", "200").timer()
77-
.count()).isEqualTo(1L);
78+
Timer timer = this.registry.get("http.server.requests").tags("status", "200")
79+
.timer();
80+
assertThat(timer.count()).isEqualTo(1L);
81+
HistogramSnapshot snapshot = timer.takeSnapshot();
82+
assertThat(snapshot.percentileValues()).hasSize(2);
83+
assertThat(snapshot.percentileValues()[0].percentile()).isEqualTo(0.5);
84+
assertThat(snapshot.percentileValues()[1].percentile()).isEqualTo(0.95);
7885
}
7986

8087
@Configuration
@@ -96,7 +103,7 @@ MeterRegistry meterRegistry(Clock clock) {
96103
public WebMvcMetricsFilter webMetricsFilter(WebApplicationContext context,
97104
MeterRegistry registry) {
98105
return new WebMvcMetricsFilter(registry, new DefaultWebMvcTagsProvider(),
99-
"http.server.requests", true);
106+
"http.server.requests", true, new double[] { 0.5, 0.95 }, true);
100107
}
101108

102109
}

spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetricsFilterTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ CyclicBarrier completableFutureBarrier() {
361361
WebMvcMetricsFilter webMetricsFilter(MeterRegistry registry,
362362
WebApplicationContext ctx) {
363363
return new WebMvcMetricsFilter(registry, new DefaultWebMvcTagsProvider(),
364-
"http.server.requests", true);
364+
"http.server.requests", true, null, false);
365365
}
366366

367367
}

spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetricsIntegrationTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ MeterRegistry meterRegistry(Clock clock) {
111111
public WebMvcMetricsFilter webMetricsFilter(MeterRegistry registry,
112112
WebApplicationContext ctx) {
113113
return new WebMvcMetricsFilter(registry, new DefaultWebMvcTagsProvider(),
114-
"http.server.requests", true);
114+
"http.server.requests", true, null, false);
115115
}
116116

117117
@RestController

0 commit comments

Comments
 (0)