You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 07:14:55