Spring Boot如何修改Prometheus http_client_request指标的uri标签值
解决Spring Boot Actuator http_client_request指标URI标签带路径参数的问题
你遇到的问题是因为默认的http_client_requests指标会使用实际请求的完整路径(带具体参数值)作为uri标签,导致同模板的请求无法聚合统计。完全可以在指标推送前修改uri标签值,以下是几种实用的解决方案:
方法一:自定义RestTemplate标签提供者(适用于RestTemplate场景)
Spring Boot通过MetricsClientHttpRequestInterceptor收集RestTemplate的请求指标,我们可以替换默认的RestTemplateExchangeTagsProvider,在生成标签时将实际路径替换为模板格式:
import io.micrometer.core.instrument.MeterRegistry; import org.springframework.boot.actuate.metrics.web.client.DefaultRestTemplateExchangeTagsProvider; import org.springframework.boot.actuate.metrics.web.client.MetricsClientHttpRequestInterceptor; import org.springframework.boot.actuate.metrics.web.client.RestTemplateExchangeTags; import org.springframework.boot.actuate.metrics.web.client.RestTemplateExchangeTagsProvider; import org.springframework.http.HttpRequest; import org.springframework.http.client.ClientHttpRequestExecution; import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.ClientHttpResponse; import org.springframework.web.client.RestTemplate; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.io.IOException; import java.util.ArrayList; import java.util.List; // 自定义标签提供者,将实际路径转换为模板路径 class CustomRestTemplateExchangeTagsProvider implements RestTemplateExchangeTagsProvider { private final DefaultRestTemplateExchangeTagsProvider defaultProvider = new DefaultRestTemplateExchangeTagsProvider(); @Override public Iterable<RestTemplateExchangeTags> getTags(String urlTemplate, HttpRequest request, ClientHttpResponse response) { // 根据业务规则替换路径参数,示例:将数字ID替换为{id} String normalizedUri = request.getURI().getPath().replaceAll("/\\d+/", "/{id}/"); // 使用处理后的模板路径生成标签 return defaultProvider.getTags(normalizedUri, request, response); } } @Configuration public class RestTemplateMetricsConfig { @Bean public RestTemplate restTemplate(MeterRegistry meterRegistry) { RestTemplate restTemplate = new RestTemplate(); List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>(restTemplate.getInterceptors()); // 移除默认的指标拦截器 interceptors.removeIf(interceptor -> interceptor instanceof MetricsClientHttpRequestInterceptor); // 添加自定义指标拦截器 MetricsClientHttpRequestInterceptor customInterceptor = new MetricsClientHttpRequestInterceptor( meterRegistry, new CustomRestTemplateExchangeTagsProvider() ); interceptors.add(customInterceptor); restTemplate.setInterceptors(interceptors); return restTemplate; } }
方法二:自定义WebClient标签提供者(适用于WebClient场景)
如果使用WebClient作为HTTP客户端,逻辑类似,自定义WebClientExchangeTagsProvider来修改uri标签:
import io.micrometer.core.instrument.MeterRegistry; import org.springframework.boot.actuate.metrics.web.reactive.client.DefaultWebClientExchangeTagsProvider; import org.springframework.boot.actuate.metrics.web.reactive.client.MetricsWebClientFilterFunction; import org.springframework.boot.actuate.metrics.web.reactive.client.WebClientExchangeTagsProvider; import org.springframework.web.reactive.function.client.ClientRequest; import org.springframework.web.reactive.function.client.ClientResponse; import org.springframework.web.reactive.function.client.WebClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; class CustomWebClientExchangeTagsProvider implements WebClientExchangeTagsProvider { private final DefaultWebClientExchangeTagsProvider defaultProvider = new DefaultWebClientExchangeTagsProvider(); @Override public Iterable<io.micrometer.core.instrument.Tag> getTags(ClientRequest request, ClientResponse response, Throwable throwable) { String normalizedUri = request.url().getPath().replaceAll("/\\d+/", "/{id}/"); // 替换请求路径后生成标签 ClientRequest modifiedRequest = ClientRequest.from(request) .url(request.url().newBuilder().path(normalizedUri).build()) .build(); return defaultProvider.getTags(modifiedRequest, response, throwable); } } @Configuration public class WebClientMetricsConfig { @Bean public WebClient webClient(MeterRegistry meterRegistry) { MetricsWebClientFilterFunction metricsFilter = new MetricsWebClientFilterFunction( meterRegistry, new CustomWebClientExchangeTagsProvider() ); return WebClient.builder() .filter(metricsFilter) .build(); } }
方法三:全局修改指标标签(无需修改客户端配置)
如果需要统一处理所有http_client_requests指标,可以使用MeterFilter在指标注册前修改uri标签:
import io.micrometer.core.instrument.Meter; import io.micrometer.core.instrument.config.MeterFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.Map; @Configuration public class GlobalMetricsConfig { @Bean public MeterFilter normalizeHttpClientUriFilter() { return new MeterFilter() { @Override public Meter.Id map(Meter.Id id) { if ("http_client_requests".equals(id.getName())) { Map<String, String> tags = id.getTagsAsMap(); String uri = tags.get("uri"); if (uri != null) { // 按规则替换路径参数 String normalizedUri = uri.replaceAll("/\\d+/", "/{id}/"); // 返回修改后的指标ID return id.withTag("uri", normalizedUri); } } return id; } }; } }
说明
- 以上三种方法都能在指标推送前完成
uri标签的修改,确保同模板的请求聚合到同一个标签下统计。 - 路径替换规则(比如
replaceAll("/\\d+/", "/{id}/"))需要根据你的实际业务路由调整,复杂场景可以使用Spring的PathMatcher来匹配模板路径。
内容的提问来源于stack exchange,提问作者Kishan
相关产品推荐
相关产品推荐

