Skip to content

Commit 0625443

Browse files
committed
Polish "Limit metrics collection of incoming requests"
Closes gh-14173
1 parent 81a6701 commit 0625443

File tree

8 files changed

+182
-113
lines changed

8 files changed

+182
-113
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
/**
3131
* {@link MeterFilter} to log only once a warning message and deny {@link Meter.Id}.
3232
*
33+
* @author Jon Schneider
3334
* @author Dmytro Nosan
3435
* @since 2.0.5
3536
*/

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

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@
5252
@ConditionalOnBean(MeterRegistry.class)
5353
public class RestTemplateMetricsAutoConfiguration {
5454

55+
private final MetricsProperties properties;
56+
57+
public RestTemplateMetricsAutoConfiguration(MetricsProperties properties) {
58+
this.properties = properties;
59+
}
60+
5561
@Bean
5662
@ConditionalOnMissingBean(RestTemplateExchangeTagsProvider.class)
5763
public DefaultRestTemplateExchangeTagsProvider restTemplateTagConfigurer() {
@@ -61,22 +67,20 @@ public DefaultRestTemplateExchangeTagsProvider restTemplateTagConfigurer() {
6167
@Bean
6268
public MetricsRestTemplateCustomizer metricsRestTemplateCustomizer(
6369
MeterRegistry meterRegistry,
64-
RestTemplateExchangeTagsProvider restTemplateTagConfigurer,
65-
MetricsProperties properties) {
70+
RestTemplateExchangeTagsProvider restTemplateTagConfigurer) {
6671
return new MetricsRestTemplateCustomizer(meterRegistry, restTemplateTagConfigurer,
67-
properties.getWeb().getClient().getRequestsMetricName());
72+
this.properties.getWeb().getClient().getRequestsMetricName());
6873
}
6974

7075
@Bean
7176
@Order(0)
72-
public MeterFilter metricsWebClientUriTagFilter(MetricsProperties properties) {
73-
String metricName = properties.getWeb().getClient().getRequestsMetricName();
74-
MeterFilter denyFilter = new OnlyOnceLoggingDenyMeterFilter(() -> String.format(
75-
"Reached the maximum number of URI tags for '%s'. "
76-
+ "Are you using uriVariables on RestTemplate calls?",
77-
metricName));
77+
public MeterFilter metricsWebClientUriTagFilter() {
78+
String metricName = this.properties.getWeb().getClient().getRequestsMetricName();
79+
MeterFilter denyFilter = new OnlyOnceLoggingDenyMeterFilter(() -> String
80+
.format("Reached the maximum number of URI tags for '%s'. Are you using "
81+
+ "'uriVariables' on RestTemplate calls?", metricName));
7882
return MeterFilter.maximumAllowableTags(metricName, "uri",
79-
properties.getWeb().getClient().getMaxUriTags(), denyFilter);
83+
this.properties.getWeb().getClient().getMaxUriTags(), denyFilter);
8084
}
8185

8286
}

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

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@
5050
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
5151
public class WebFluxMetricsAutoConfiguration {
5252

53+
private final MetricsProperties properties;
54+
55+
public WebFluxMetricsAutoConfiguration(MetricsProperties properties) {
56+
this.properties = properties;
57+
}
58+
5359
@Bean
5460
@ConditionalOnMissingBean(WebFluxTagsProvider.class)
5561
public DefaultWebFluxTagsProvider webfluxTagConfigurer() {
@@ -58,19 +64,19 @@ public DefaultWebFluxTagsProvider webfluxTagConfigurer() {
5864

5965
@Bean
6066
public MetricsWebFilter webfluxMetrics(MeterRegistry registry,
61-
WebFluxTagsProvider tagConfigurer, MetricsProperties properties) {
67+
WebFluxTagsProvider tagConfigurer) {
6268
return new MetricsWebFilter(registry, tagConfigurer,
63-
properties.getWeb().getServer().getRequestsMetricName());
69+
this.properties.getWeb().getServer().getRequestsMetricName());
6470
}
6571

6672
@Bean
6773
@Order(0)
68-
public MeterFilter metricsHttpServerUriTagFilter(MetricsProperties properties) {
69-
String metricName = properties.getWeb().getServer().getRequestsMetricName();
74+
public MeterFilter metricsHttpServerUriTagFilter() {
75+
String metricName = this.properties.getWeb().getServer().getRequestsMetricName();
7076
MeterFilter filter = new OnlyOnceLoggingDenyMeterFilter(() -> String
7177
.format("Reached the maximum number of URI tags for '%s'.", metricName));
7278
return MeterFilter.maximumAllowableTags(metricName, "uri",
73-
properties.getWeb().getServer().getMaxUriTags(), filter);
79+
this.properties.getWeb().getServer().getMaxUriTags(), filter);
7480
}
7581

7682
}

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

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@
6161
@EnableConfigurationProperties(MetricsProperties.class)
6262
public class WebMvcMetricsAutoConfiguration {
6363

64+
private final MetricsProperties properties;
65+
66+
public WebMvcMetricsAutoConfiguration(MetricsProperties properties) {
67+
this.properties = properties;
68+
}
69+
6470
@Bean
6571
@ConditionalOnMissingBean(WebMvcTagsProvider.class)
6672
public DefaultWebMvcTagsProvider webMvcTagsProvider() {
@@ -69,9 +75,9 @@ public DefaultWebMvcTagsProvider webMvcTagsProvider() {
6975

7076
@Bean
7177
public FilterRegistrationBean<WebMvcMetricsFilter> webMvcMetricsFilter(
72-
MeterRegistry registry, MetricsProperties properties,
73-
WebMvcTagsProvider tagsProvider, WebApplicationContext context) {
74-
Server serverProperties = properties.getWeb().getServer();
78+
MeterRegistry registry, WebMvcTagsProvider tagsProvider,
79+
WebApplicationContext context) {
80+
Server serverProperties = this.properties.getWeb().getServer();
7581
WebMvcMetricsFilter filter = new WebMvcMetricsFilter(context, registry,
7682
tagsProvider, serverProperties.getRequestsMetricName(),
7783
serverProperties.isAutoTimeRequests());
@@ -84,12 +90,12 @@ public FilterRegistrationBean<WebMvcMetricsFilter> webMvcMetricsFilter(
8490

8591
@Bean
8692
@Order(0)
87-
public MeterFilter metricsHttpServerUriTagFilter(MetricsProperties properties) {
88-
String metricName = properties.getWeb().getServer().getRequestsMetricName();
93+
public MeterFilter metricsHttpServerUriTagFilter() {
94+
String metricName = this.properties.getWeb().getServer().getRequestsMetricName();
8995
MeterFilter filter = new OnlyOnceLoggingDenyMeterFilter(() -> String
9096
.format("Reached the maximum number of URI tags for '%s'.", metricName));
9197
return MeterFilter.maximumAllowableTags(metricName, "uri",
92-
properties.getWeb().getServer().getMaxUriTags(), filter);
98+
this.properties.getWeb().getServer().getMaxUriTags(), filter);
9399
}
94100

95101
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2012-2018 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+
* http://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.autoconfigure.metrics.web;
18+
19+
import org.springframework.web.bind.annotation.GetMapping;
20+
import org.springframework.web.bind.annotation.RestController;
21+
22+
/**
23+
* Test controller used by metrics tests.
24+
*
25+
* @author Dmytro Nosan
26+
* @author Stephane Nicoll
27+
*/
28+
@RestController
29+
public class TestController {
30+
31+
@GetMapping("test0")
32+
public String test0() {
33+
return "test0";
34+
}
35+
36+
@GetMapping("test1")
37+
public String test1() {
38+
return "test1";
39+
}
40+
41+
@GetMapping("test2")
42+
public String test2() {
43+
return "test2";
44+
}
45+
46+
}

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

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@
2020
import org.junit.Rule;
2121
import org.junit.Test;
2222

23-
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties;
2423
import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun;
2524
import org.springframework.boot.actuate.metrics.web.client.MetricsRestTemplateCustomizer;
2625
import org.springframework.boot.autoconfigure.AutoConfigurations;
2726
import org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration;
27+
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
2828
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
2929
import org.springframework.boot.test.rule.OutputCapture;
3030
import org.springframework.boot.web.client.RestTemplateBuilder;
@@ -76,31 +76,45 @@ public void restTemplateCanBeCustomizedManually() {
7676
@Test
7777
public void afterMaxUrisReachedFurtherUrisAreDenied() {
7878
this.contextRunner
79-
.withPropertyValues("management.metrics.web.client.max-uri-tags=10")
79+
.withPropertyValues("management.metrics.web.client.max-uri-tags=2")
8080
.run((context) -> {
81-
MetricsProperties properties = context
82-
.getBean(MetricsProperties.class);
83-
int maxUriTags = properties.getWeb().getClient().getMaxUriTags();
84-
MeterRegistry registry = context.getBean(MeterRegistry.class);
85-
RestTemplate restTemplate = context.getBean(RestTemplateBuilder.class)
86-
.build();
87-
MockRestServiceServer server = MockRestServiceServer
88-
.createServer(restTemplate);
89-
for (int i = 0; i < maxUriTags + 10; i++) {
90-
server.expect(requestTo("/test/" + i))
91-
.andRespond(withStatus(HttpStatus.OK));
92-
}
93-
for (int i = 0; i < maxUriTags + 10; i++) {
94-
restTemplate.getForObject("/test/" + i, String.class);
95-
}
96-
assertThat(registry.get("http.client.requests").meters())
97-
.hasSize(maxUriTags);
98-
assertThat(this.out.toString())
99-
.contains("Reached the maximum number of URI tags "
100-
+ "for 'http.client.requests'. Are you using uriVariables on RestTemplate calls?");
81+
MeterRegistry registry = getInitializedMeterRegistry(context);
82+
assertThat(registry.get("http.client.requests").meters()).hasSize(2);
83+
assertThat(this.out.toString()).contains(
84+
"Reached the maximum number of URI tags for 'http.client.requests'.");
85+
assertThat(this.out.toString()).contains(
86+
"Are you using 'uriVariables' on RestTemplate calls?");
10187
});
10288
}
10389

90+
@Test
91+
public void shouldNotDenyNorLogIfMaxUrisIsNotReached() {
92+
this.contextRunner
93+
.withPropertyValues("management.metrics.web.client.max-uri-tags=5")
94+
.run((context) -> {
95+
MeterRegistry registry = getInitializedMeterRegistry(context);
96+
assertThat(registry.get("http.client.requests").meters()).hasSize(3);
97+
assertThat(this.out.toString()).doesNotContain(
98+
"Reached the maximum number of URI tags for 'http.client.requests'.");
99+
assertThat(this.out.toString()).doesNotContain(
100+
"Are you using 'uriVariables' on RestTemplate calls?");
101+
});
102+
}
103+
104+
private MeterRegistry getInitializedMeterRegistry(
105+
AssertableApplicationContext context) {
106+
MeterRegistry registry = context.getBean(MeterRegistry.class);
107+
RestTemplate restTemplate = context.getBean(RestTemplateBuilder.class).build();
108+
MockRestServiceServer server = MockRestServiceServer.createServer(restTemplate);
109+
for (int i = 0; i < 3; i++) {
110+
server.expect(requestTo("/test/" + i)).andRespond(withStatus(HttpStatus.OK));
111+
}
112+
for (int i = 0; i < 3; i++) {
113+
restTemplate.getForObject("/test/" + i, String.class);
114+
}
115+
return registry;
116+
}
117+
104118
private void validateRestTemplate(RestTemplate restTemplate, MeterRegistry registry) {
105119
MockRestServiceServer server = MockRestServiceServer.createServer(restTemplate);
106120
server.expect(requestTo("/test")).andRespond(withStatus(HttpStatus.OK));

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

Lines changed: 27 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,21 @@
1919
import io.micrometer.core.instrument.MeterRegistry;
2020
import org.junit.Rule;
2121
import org.junit.Test;
22-
import reactor.core.publisher.Mono;
2322

2423
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
2524
import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration;
25+
import org.springframework.boot.actuate.autoconfigure.metrics.web.TestController;
2626
import org.springframework.boot.actuate.metrics.web.reactive.server.DefaultWebFluxTagsProvider;
2727
import org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter;
2828
import org.springframework.boot.actuate.metrics.web.reactive.server.WebFluxTagsProvider;
2929
import org.springframework.boot.autoconfigure.AutoConfigurations;
3030
import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration;
31+
import org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext;
3132
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
3233
import org.springframework.boot.test.rule.OutputCapture;
3334
import org.springframework.context.annotation.Bean;
3435
import org.springframework.context.annotation.Configuration;
3536
import org.springframework.test.web.reactive.server.WebTestClient;
36-
import org.springframework.web.bind.annotation.GetMapping;
37-
import org.springframework.web.bind.annotation.RestController;
3837

3938
import static org.assertj.core.api.Assertions.assertThat;
4039
import static org.mockito.Mockito.mock;
@@ -77,21 +76,38 @@ public void afterMaxUrisReachedFurtherUrisAreDenied() {
7776
.withUserConfiguration(TestController.class)
7877
.withPropertyValues("management.metrics.web.server.max-uri-tags=2")
7978
.run((context) -> {
80-
WebTestClient webTestClient = WebTestClient
81-
.bindToApplicationContext(context).build();
82-
83-
for (int i = 0; i < 3; i++) {
84-
webTestClient.get().uri("/test" + i).exchange().expectStatus()
85-
.isOk();
86-
}
87-
MeterRegistry registry = context.getBean(MeterRegistry.class);
79+
MeterRegistry registry = getInitializedMeterRegistry(context);
8880
assertThat(registry.get("http.server.requests").meters()).hasSize(2);
8981
assertThat(this.output.toString())
9082
.contains("Reached the maximum number of URI tags "
9183
+ "for 'http.server.requests'");
9284
});
9385
}
9486

87+
@Test
88+
public void shouldNotDenyNorLogIfMaxUrisIsNotReached() {
89+
this.contextRunner
90+
.withConfiguration(AutoConfigurations.of(WebFluxAutoConfiguration.class))
91+
.withUserConfiguration(TestController.class)
92+
.withPropertyValues("management.metrics.web.server.max-uri-tags=5")
93+
.run((context) -> {
94+
MeterRegistry registry = getInitializedMeterRegistry(context);
95+
assertThat(registry.get("http.server.requests").meters()).hasSize(3);
96+
assertThat(this.output.toString()).doesNotContain(
97+
"Reached the maximum number of URI tags for 'http.server.requests'");
98+
});
99+
}
100+
101+
private MeterRegistry getInitializedMeterRegistry(
102+
AssertableReactiveWebApplicationContext context) {
103+
WebTestClient webTestClient = WebTestClient.bindToApplicationContext(context)
104+
.build();
105+
for (int i = 0; i < 3; i++) {
106+
webTestClient.get().uri("/test" + i).exchange().expectStatus().isOk();
107+
}
108+
return context.getBean(MeterRegistry.class);
109+
}
110+
95111
@Configuration
96112
protected static class CustomWebFluxTagsProviderConfig {
97113

@@ -102,24 +118,4 @@ public WebFluxTagsProvider customWebFluxTagsProvider() {
102118

103119
}
104120

105-
@RestController
106-
static class TestController {
107-
108-
@GetMapping("test0")
109-
public Mono<String> test0() {
110-
return Mono.just("test0");
111-
}
112-
113-
@GetMapping("test1")
114-
public Mono<String> test1() {
115-
return Mono.just("test1");
116-
}
117-
118-
@GetMapping("test2")
119-
public Mono<String> test2() {
120-
return Mono.just("test2");
121-
}
122-
123-
}
124-
125121
}

0 commit comments

Comments
 (0)