Auto-configure SpanTagAnnotationHandler

Closes gh-38662
This commit is contained in:
Moritz Halbritter 2023-12-06 13:52:56 +01:00
parent a7d88b69d4
commit c4be302fdb
2 changed files with 45 additions and 8 deletions

View File

@ -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> 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);
}
}
}
}

View File

@ -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)