From c4be302fdbe515266a674ce9b25739627f3e71fa Mon Sep 17 00:00:00 2001 From: Moritz Halbritter Date: Wed, 6 Dec 2023 13:52:56 +0100 Subject: [PATCH] Auto-configure SpanTagAnnotationHandler Closes gh-38662 --- .../MicrometerTracingAutoConfiguration.java | 40 +++++++++++++++---- ...crometerTracingAutoConfigurationTests.java | 13 +++++- 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/MicrometerTracingAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/MicrometerTracingAutoConfiguration.java index 93d8acaa0e3..e255f47c6f9 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/MicrometerTracingAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/MicrometerTracingAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.springframework.boot.actuate.autoconfigure.tracing; +import io.micrometer.common.annotation.ValueExpressionResolver; import io.micrometer.tracing.Tracer; import io.micrometer.tracing.annotation.DefaultNewSpanParser; import io.micrometer.tracing.annotation.ImperativeMethodInvocationProcessor; @@ -29,7 +30,7 @@ import io.micrometer.tracing.handler.PropagatingSenderTracingObservationHandler; import io.micrometer.tracing.propagation.Propagator; import org.aspectj.weaver.Advice; -import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.BeanFactory; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; @@ -39,6 +40,10 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.SimpleEvaluationContext; /** * {@link EnableAutoConfiguration Auto-configuration} for the Micrometer Tracing API. @@ -104,14 +109,18 @@ public class MicrometerTracingAutoConfiguration { return new DefaultNewSpanParser(); } + @Bean + @ConditionalOnMissingBean + SpanTagAnnotationHandler spanTagAnnotationHandler(BeanFactory beanFactory) { + ValueExpressionResolver valueExpressionResolver = new SpelTagValueExpressionResolver(); + return new SpanTagAnnotationHandler(beanFactory::getBean, (ignored) -> valueExpressionResolver); + } + @Bean @ConditionalOnMissingBean(MethodInvocationProcessor.class) ImperativeMethodInvocationProcessor imperativeMethodInvocationProcessor(NewSpanParser newSpanParser, - Tracer tracer, ObjectProvider spanTagAnnotationHandler) { - ImperativeMethodInvocationProcessor methodInvocationProcessor = new ImperativeMethodInvocationProcessor( - newSpanParser, tracer); - spanTagAnnotationHandler.ifAvailable(methodInvocationProcessor::setSpanTagAnnotationHandler); - return methodInvocationProcessor; + Tracer tracer, SpanTagAnnotationHandler spanTagAnnotationHandler) { + return new ImperativeMethodInvocationProcessor(newSpanParser, tracer, spanTagAnnotationHandler); } @Bean @@ -122,4 +131,21 @@ public class MicrometerTracingAutoConfiguration { } + private static class SpelTagValueExpressionResolver implements ValueExpressionResolver { + + @Override + public String resolve(String expression, Object parameter) { + try { + SimpleEvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build(); + ExpressionParser expressionParser = new SpelExpressionParser(); + Expression expressionToEvaluate = expressionParser.parseExpression(expression); + return expressionToEvaluate.getValue(context, parameter, String.class); + } + catch (Exception ex) { + throw new IllegalStateException("Unable to evaluate SpEL expression '%s'".formatted(expression), ex); + } + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/MicrometerTracingAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/MicrometerTracingAutoConfigurationTests.java index 9c6c61f6f01..70024c57ba5 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/MicrometerTracingAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/MicrometerTracingAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,8 @@ package org.springframework.boot.actuate.autoconfigure.tracing; import java.util.List; +import io.micrometer.common.annotation.ValueExpressionResolver; +import io.micrometer.common.annotation.ValueResolver; import io.micrometer.tracing.Tracer; import io.micrometer.tracing.annotation.DefaultNewSpanParser; import io.micrometer.tracing.annotation.ImperativeMethodInvocationProcessor; @@ -63,6 +65,7 @@ class MicrometerTracingAutoConfigurationTests { assertThat(context).hasSingleBean(DefaultNewSpanParser.class); assertThat(context).hasSingleBean(ImperativeMethodInvocationProcessor.class); assertThat(context).hasSingleBean(SpanAspect.class); + assertThat(context).hasSingleBean(SpanTagAnnotationHandler.class); }); } @@ -100,6 +103,8 @@ class MicrometerTracingAutoConfigurationTests { assertThat(context).hasSingleBean(ImperativeMethodInvocationProcessor.class); assertThat(context).hasBean("customSpanAspect"); assertThat(context).hasSingleBean(SpanAspect.class); + assertThat(context).hasBean("customSpanTagAnnotationHandler"); + assertThat(context).hasSingleBean(SpanTagAnnotationHandler.class); }); } @@ -215,6 +220,12 @@ class MicrometerTracingAutoConfigurationTests { return new SpanAspect(methodInvocationProcessor); } + @Bean + SpanTagAnnotationHandler customSpanTagAnnotationHandler() { + return new SpanTagAnnotationHandler((aClass) -> mock(ValueResolver.class), + (aClass) -> mock(ValueExpressionResolver.class)); + } + } @Configuration(proxyBeanMethods = false)