Micrometer WebMvcTagsContributor生产环境无法添加自定义标签排查
问题:Spring Boot生产环境下Micrometer自定义路径变量标签不生效
背景
我使用Spring Boot(Java 16)开发时,尝试为Micrometer生成的指标添加请求路径变量作为自定义标签。经调研,创建WebMvcTagsContributor类型的Bean可实现该需求,以下是实现代码:
自定义WebMvcTagsContributor实现
public class CustomWebMvcTagsContributor implements WebMvcTagsContributor { private static int PRINT_ERROR_COUNTER = 0; @Override public Iterable<Tag> getTags(HttpServletRequest request, HttpServletResponse response, Object handler, Throwable exception) { return Tags.of(getAllTags(request)); } private static List<Tag> getAllTags(HttpServletRequest request) { Object attributesMapObject = request.getAttribute(View.PATH_VARIABLES); if (isNull(attributesMapObject)) { attributesMapObject = request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE); if (isNull(attributesMapObject)) { attributesMapObject = extractPathVariablesFromURI(request); } } if (nonNull(attributesMapObject)) { return getPathVariablesTags(attributesMapObject); } return List.of(); } private static Object extractPathVariablesFromURI(HttpServletRequest request) { Long currentUserId = SecurityUtils.getCurrentUserId().orElse(null); try { URI uri = new URI(request.getRequestURI()); String path = uri.getPath(); //get the path UriTemplate uriTemplate = new UriTemplate((String) request.getAttribute( HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE)); //create template return uriTemplate.match(path); //extract values form template } catch (Exception e) { log.warn("[Error on 3rd attempt]", e); } return null; } private static List<Tag> getPathVariablesTags(Object attributesMapObject) { try { Long currentUserId = SecurityUtils.getCurrentUserId().orElse(null); if (nonNull(attributesMapObject)) { var attributesMap = (Map<String, Object>) attributesMapObject; List<Tag> tags = attributesMap.entrySet().stream() .map(stringObjectEntry -> Tag.of(stringObjectEntry.getKey(), String.valueOf(stringObjectEntry.getValue()))) .toList(); log.warn("[CustomTags] [{}]", CommonUtils.toJson(tags)); return tags; } } catch (Exception e) { if (PRINT_ERROR_COUNTER < 5) { log.error("[Error while getting attributes map object]", e); PRINT_ERROR_COUNTER++; } } return List.of(); } @Override public Iterable<Tag> getLongRequestTags(HttpServletRequest request, Object handler) { return null; } }
Bean配置代码
@Bean public WebMvcTagsContributor webMvcTagsContributor() { return new CustomWebMvcTagsContributor(); }
本地与生产表现差异
- 本地测试项目正常,指标包含自定义路径变量标签:
http_server_requests_seconds_count {exception="None", method="GET",id="123",outcome="Success",status="200",test="test",uri="/test/{id}/compute/{test}",)1.0
- 生产环境(独立的大型应用)仅生成默认指标,无自定义标签:
http_server_requests_seconds_count {exception="None", method="GET",outcome="Success",status="200",uri="/api/{something}/test",)1.0
已尝试的无效方案
- 改用实现
WebMvcTagsProvider的Bean:本地正常,但生产环境带路径变量的端点无法生成指标; - 添加日志查看自定义标签内容:无日志输出(已排除当前用户ID相关影响)。
排查方向建议
- Bean加载验证:检查生产环境中
CustomWebMvcTagsContributor是否被Spring容器正确初始化。可在Bean构造函数添加初始化日志,或通过Spring Boot Actuator的/beans端点确认Bean存在性; - 请求属性差异检查:生产环境可能存在额外过滤器、拦截器(如网关、安全组件),导致
View.PATH_VARIABLES、HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE等请求属性丢失。在getAllTags方法开头打印所有请求属性,对比本地与生产的差异; - 依赖版本一致性:确认生产环境的Micrometer、Spring Boot版本与本地完全一致,避免版本差异导致接口逻辑不兼容或依赖冲突;
- 端点类型兼容性:检查生产环境出现问题的端点是否为异步处理、特殊映射类型,这类场景可能导致路径变量属性未被正确设置;
- 日志级别调整:生产环境日志级别可能高于本地(如仅打印ERROR),导致自定义代码中的WARN日志无法输出。临时调整日志级别至WARN/DEBUG,确认自定义代码是否被执行;
- Bean优先级检查:生产环境可能存在其他
WebMvcTagsContributor或WebMvcTagsProvider实现Bean,覆盖了自定义Bean。可给自定义Bean添加@Primary注解提升优先级,或检查容器中同类型Bean的数量; - 路径变量提取逻辑排查:在
extractPathVariablesFromURI方法中添加更详细的异常日志,确认生产环境中该方法是否因URI格式、BEST_MATCHING_PATTERN_ATTRIBUTE值异常而执行失败。
内容的提问来源于stack exchange,提问作者ALex
相关产品推荐
相关产品推荐

