Following up on #48655 (closed for inactivity). @snicoll raised valid concerns about scope — this is a narrower proposal based on implementation experience.
Problem
Spring Boot provides RED metrics for HTTP clients via http.client.requests, but connection pool utilization (USE metrics) is not observable. Pool exhaustion is only visible after the fact, when connectionRequestTimeout fires and surfaces as an error in http.client.requests. There is no way to see saturation building before requests start failing.
The httpclient5-observation module (5.6+) provides pool gauges (http.client.pool.leased, .available, .pending) that fill this gap.
Proposal: enable CONN_POOL only, not BASIC or IO
@snicoll's concern about duplicate traces is valid — BASIC adds a request timer (http.client.request) that overlaps with Spring Boot's http.client.requests observation. Enabling BASIC would produce two similar-looking timers that are hard to distinguish in dashboards. The same applies to the inflight gauge in BASIC, which overlaps with http.client.requests.active.
CONN_POOL is the only metric group that provides genuinely new information. It could be auto-configured with minimal surface area:
@Bean
@ConditionalOnBean(MeterRegistry.class)
@ConditionalOnProperty(name = "spring.http.client.pool-metrics.enabled", matchIfMissing = true)
ClientHttpRequestFactoryBuilderCustomizer<HttpComponentsClientHttpRequestFactoryBuilder>
poolMetricsCustomizer(MeterRegistry meterRegistry, ObjectProvider<ObservationRegistry> observationRegistry) {
var options = ObservingOptions.builder()
.metrics(EnumSet.of(ObservingOptions.MetricSet.CONN_POOL))
.build();
return builder -> builder.withHttpClientCustomizer(b ->
HttpClientObservationSupport.enable(b, observationRegistry.getIfAvailable(),
meterRegistry, options, MetricConfig.DEFAULT));
}
Pitfall: client.name tag cardinality
ConnPoolMeters registers gauges with only the MetricConfig.commonTags — no client identifier by default. This works for a single pool but breaks with multiple RestClient beans: all pools register gauges under the same metric name and tags, silently overwriting each other in the registry.
For the ClientHttpRequestFactoryBuilderCustomizer path this is especially problematic because RestClient.Builder is prototype-scoped. Every injection creates a new pool with identical, indistinguishable gauges.
A useful auto-configuration would need to either:
- Only register pool gauges when a client name is known (e.g., via the HTTP service group name in Spring Boot 4's
RestClientHttpServiceGroupConfigurer)
- Or add a
client.name tag derived from the base URL host, matching the client.name tag on http.client.requests so pool and request metrics can be correlated on dashboards
Without sufficient cardinality on the client.name tag, the gauges are ambiguous in any service with more than one HTTP client.
Summary
- Scope:
CONN_POOL only (no trace duplication, no timer overlap)
- Single kill switch property
- Main challenge: ensuring each pool's gauges carry a distinguishing tag that correlates with
http.client.requests
Following up on #48655 (closed for inactivity). @snicoll raised valid concerns about scope — this is a narrower proposal based on implementation experience.
Problem
Spring Boot provides RED metrics for HTTP clients via
http.client.requests, but connection pool utilization (USE metrics) is not observable. Pool exhaustion is only visible after the fact, whenconnectionRequestTimeoutfires and surfaces as an error inhttp.client.requests. There is no way to see saturation building before requests start failing.The
httpclient5-observationmodule (5.6+) provides pool gauges (http.client.pool.leased,.available,.pending) that fill this gap.Proposal: enable CONN_POOL only, not BASIC or IO
@snicoll's concern about duplicate traces is valid —
BASICadds a request timer (http.client.request) that overlaps with Spring Boot'shttp.client.requestsobservation. EnablingBASICwould produce two similar-looking timers that are hard to distinguish in dashboards. The same applies to theinflightgauge inBASIC, which overlaps withhttp.client.requests.active.CONN_POOLis the only metric group that provides genuinely new information. It could be auto-configured with minimal surface area:Pitfall:
client.nametag cardinalityConnPoolMetersregisters gauges with only theMetricConfig.commonTags— no client identifier by default. This works for a single pool but breaks with multipleRestClientbeans: all pools register gauges under the same metric name and tags, silently overwriting each other in the registry.For the
ClientHttpRequestFactoryBuilderCustomizerpath this is especially problematic becauseRestClient.Builderis prototype-scoped. Every injection creates a new pool with identical, indistinguishable gauges.A useful auto-configuration would need to either:
RestClientHttpServiceGroupConfigurer)client.nametag derived from the base URL host, matching theclient.nametag onhttp.client.requestsso pool and request metrics can be correlated on dashboardsWithout sufficient cardinality on the
client.nametag, the gauges are ambiguous in any service with more than one HTTP client.Summary
CONN_POOLonly (no trace duplication, no timer overlap)http.client.requests