SpringBoot 2.x升级至3.3.3:指标模块兼容性问题咨询
解决SpringBoot 3.3.3中
http.server.requests指标恢复2.x样式的规范方案 核心思路
SpringBoot 3.x采用Micrometer Observation框架替代了旧的Metrics模型,http.server.requests的标签由ServerRequestObservationConvention组件控制。要恢复2.x版本包含error、exception标签的样式,只需自定义该Convention并注册为Spring Bean,复用默认逻辑的同时补充所需标签即可。
实现步骤
1. 自定义Observation Convention
创建类实现ServerRequestObservationConvention,在复用默认标签逻辑的基础上,添加error和exception标签的生成逻辑,覆盖所有异常场景(包括Controller抛出的业务异常、Spring Security拦截的401/403异常):
import io.micrometer.common.KeyValue; import io.micrometer.common.KeyValues; import org.springframework.http.server.observation.DefaultServerRequestObservationConvention; import org.springframework.http.server.observation.ServerRequestObservationContext; import org.springframework.http.server.observation.ServerRequestObservationConvention; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import javax.servlet.http.HttpServletRequest; import java.util.Optional; public class LegacyServerRequestObservationConvention implements ServerRequestObservationConvention { // 复用默认实现,避免重复编写基础标签逻辑 private final ServerRequestObservationConvention delegate = new DefaultServerRequestObservationConvention(); @Override public KeyValues getLowCardinalityKeyValues(ServerRequestObservationContext context) { // 在默认标签集合中追加error和exception标签 return delegate.getLowCardinalityKeyValues(context) .and(getErrorKeyValue(context)) .and(getExceptionKeyValue(context)); } @Override public KeyValues getHighCardinalityKeyValues(ServerRequestObservationContext context) { return delegate.getHighCardinalityKeyValues(context); } @Override public String getName() { return delegate.getName(); } @Override public String getContextualName(ServerRequestObservationContext context) { return delegate.getContextualName(context); } // 生成error标签:取异常类名,无异常则为"none" private KeyValue getErrorKeyValue(ServerRequestObservationContext context) { String errorValue = Optional.ofNullable(getExceptionFromContext(context)) .map(Throwable::getClass) .map(Class::getSimpleName) .orElse("none"); return KeyValue.of("error", errorValue); } // 生成exception标签:取异常全类名,无异常则为"none" private KeyValue getExceptionKeyValue(ServerRequestObservationContext context) { Throwable exception = getExceptionFromContext(context); String exceptionValue = exception != null ? exception.getClass().getName() : "none"; return KeyValue.of("exception", exceptionValue); } // 从上下文或请求属性中获取异常,兼容Spring Security场景 private Throwable getExceptionFromContext(ServerRequestObservationContext context) { // 优先从Observation Context获取Controller抛出的异常 if (context.getError() != null) { return context.getError(); } // 从请求属性获取Spring Security处理的401/403等异常 HttpServletRequest request = (HttpServletRequest) context.getCarrier(); RequestAttributes attributes = RequestContextHolder.getRequestAttributes(); if (attributes != null) { return (Throwable) attributes.getAttribute("javax.servlet.error.exception", RequestAttributes.SCOPE_REQUEST); } return (Throwable) request.getAttribute("javax.servlet.error.exception"); } }
2. 注册自定义Convention为Bean
在配置类中注册该Bean,Spring Boot会自动替换默认的ServerRequestObservationConvention实现:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.server.observation.ServerRequestObservationConvention; @Configuration public class MetricsConfig { @Bean public ServerRequestObservationConvention legacyServerRequestObservationConvention() { return new LegacyServerRequestObservationConvention(); } }
方案优势
- 无侵入:无需修改业务代码、异常处理器或过滤器,完全基于Spring Boot扩展机制实现
- 全覆盖:同时处理Controller业务异常和Spring Security拦截的401/403异常场景
- 规范合规:遵循Micrometer Observation的官方扩展规范,避免临时方案带来的维护隐患
- 兼容性:与Spring Boot 3.x的Metrics体系完全兼容,不会影响其他指标的采集逻辑
内容的提问来源于stack exchange,提问作者AndreiM
相关产品推荐
相关产品推荐

