Spring Boot 2.7迁移3.1后WebClient指标URI标签未填充问题
WebClient 指标 URI 标签显示为
none 的排查思路 1. 确认 URI 模板的写法规范
WebClient 的观测指标能填充 URI 标签,核心依赖请求时使用带变量占位符的 URI 模板(如 get("/api/users/{id}")),而非直接拼接字符串(如 get("/api/users/" + userId))。硬编码拼接的 URI 无法被观测器识别为模板,会直接显示 none。
检查你的 MyClient 请求代码:
// 正确写法:使用占位符传递参数 webClient.get().uri("/api/users/{id}", userId) // 错误写法:直接拼接字符串 webClient.get().uri("/api/users/" + userId)
2. 验证观测配置的加载状态
Spring Boot 3.x 采用 Micrometer Observation 替代旧的指标收集逻辑,需确认以下配置和依赖:
- 确认
management.observation.web.client.enabled=true(默认开启,可显式配置确保生效) - 项目已引入
micrometer-observation和对应注册中心依赖(如micrometer-registry-prometheus)
3. 检查 WebClient 初始化逻辑
确保在 MyClient 中没有覆盖自动配置的观测过滤器。如果手动调用 webClientBuilder.filter() 时,使用了 filters(f -> f.clear()) 这类清空过滤器链的操作,会删掉自动配置的 ObservationWebClientFilter,导致 URI 标签无法被捕获。
正确的自定义姿势是保留原有过滤器链:
// MyClient 初始化示例 public MyClient(WebClient.Builder builder, ClientProperties props) { this.webClient = builder .baseUrl(props.getBaseUrl()) // 添加自定义过滤器,但不清空原有链 .filter((request, next) -> { // 自定义逻辑 return next.exchange(request); }) .build(); }
4. 排查自定义 ObservationWebClientCustomizer 的实现
如果自定义了 ObservationWebClientCustomizer,需确认没有覆盖默认的 URI 标签提取逻辑。正确的自定义应该是增强而非替换原有逻辑:
@Component public class CustomWebClientObservationCustomizer implements ObservationWebClientCustomizer { @Override public void customize(ObservationRegistry registry) { WebClientObservationConvention customConvention = new DefaultWebClientObservationConvention() { @Override public Map<String, String> getLowCardinalityKeyValues(WebClientObservationContext context) { // 先调用父类方法保留默认标签(包括URI) Map<String, String> keyValues = super.getLowCardinalityKeyValues(context); // 添加自定义标签 keyValues.put("custom.tag", "value"); return keyValues; } }; ObservationRegistries.registerObservationConvention(registry, customConvention); } }
若完全重写 getLowCardinalityKeyValues 且未调用 super,会丢失默认的 URI 标签提取逻辑。
5. 调试观测上下文
添加 ObservationListener 查看观测上下文内容,确认 URI 模板是否被正确捕获:
@Component public class WebClientObservationListener implements ObservationListener<WebClientObservationContext> { private static final Logger log = LoggerFactory.getLogger(WebClientObservationListener.class); @Override public void onStart(Observation.Context context) { if (context instanceof WebClientObservationContext webCtx) { log.debug("URI Template: {}", webCtx.getUriTemplate()); log.debug("Request URI: {}", webCtx.getRequest().getURI()); } } }
如果日志中 uriTemplate 为 null,说明请求未使用模板写法,回到第一步排查。
内容的提问来源于stack exchange,提问作者Nordine
相关产品推荐
相关产品推荐

