Add an option to disable automatic kafka interceptor configuration in spring starter (#12833)
This commit is contained in:
parent
81c7713bb2
commit
c2c5d80f72
|
@ -5,43 +5,55 @@
|
||||||
|
|
||||||
package io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.kafka;
|
package io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.kafka;
|
||||||
|
|
||||||
import io.opentelemetry.api.OpenTelemetry;
|
|
||||||
import io.opentelemetry.instrumentation.spring.kafka.v2_7.SpringKafkaTelemetry;
|
import io.opentelemetry.instrumentation.spring.kafka.v2_7.SpringKafkaTelemetry;
|
||||||
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
|
import java.lang.reflect.Field;
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
import java.util.function.Supplier;
|
||||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||||
|
import org.springframework.kafka.config.AbstractKafkaListenerContainerFactory;
|
||||||
import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;
|
import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;
|
||||||
|
import org.springframework.kafka.listener.BatchInterceptor;
|
||||||
|
import org.springframework.kafka.listener.RecordInterceptor;
|
||||||
|
|
||||||
class ConcurrentKafkaListenerContainerFactoryPostProcessor implements BeanPostProcessor {
|
class ConcurrentKafkaListenerContainerFactoryPostProcessor implements BeanPostProcessor {
|
||||||
|
|
||||||
private final ObjectProvider<OpenTelemetry> openTelemetryProvider;
|
private final Supplier<SpringKafkaTelemetry> springKafkaTelemetry;
|
||||||
private final ObjectProvider<ConfigProperties> configPropertiesProvider;
|
|
||||||
|
|
||||||
ConcurrentKafkaListenerContainerFactoryPostProcessor(
|
ConcurrentKafkaListenerContainerFactoryPostProcessor(
|
||||||
ObjectProvider<OpenTelemetry> openTelemetryProvider,
|
Supplier<SpringKafkaTelemetry> springKafkaTelemetry) {
|
||||||
ObjectProvider<ConfigProperties> configPropertiesProvider) {
|
this.springKafkaTelemetry = springKafkaTelemetry;
|
||||||
this.openTelemetryProvider = openTelemetryProvider;
|
|
||||||
this.configPropertiesProvider = configPropertiesProvider;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public Object postProcessAfterInitialization(Object bean, String beanName) {
|
public Object postProcessAfterInitialization(Object bean, String beanName) {
|
||||||
if (!(bean instanceof ConcurrentKafkaListenerContainerFactory)) {
|
if (!(bean instanceof ConcurrentKafkaListenerContainerFactory)) {
|
||||||
return bean;
|
return bean;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConcurrentKafkaListenerContainerFactory<?, ?> listenerContainerFactory =
|
ConcurrentKafkaListenerContainerFactory<Object, Object> listenerContainerFactory =
|
||||||
(ConcurrentKafkaListenerContainerFactory<?, ?>) bean;
|
(ConcurrentKafkaListenerContainerFactory<Object, Object>) bean;
|
||||||
SpringKafkaTelemetry springKafkaTelemetry =
|
SpringKafkaTelemetry springKafkaTelemetry = this.springKafkaTelemetry.get();
|
||||||
SpringKafkaTelemetry.builder(openTelemetryProvider.getObject())
|
|
||||||
.setCaptureExperimentalSpanAttributes(
|
// use reflection to read existing values to avoid overwriting user configured interceptors
|
||||||
configPropertiesProvider
|
BatchInterceptor<Object, Object> batchInterceptor =
|
||||||
.getObject()
|
readField(listenerContainerFactory, "batchInterceptor", BatchInterceptor.class);
|
||||||
.getBoolean("otel.instrumentation.kafka.experimental-span-attributes", false))
|
RecordInterceptor<Object, Object> recordInterceptor =
|
||||||
.build();
|
readField(listenerContainerFactory, "recordInterceptor", RecordInterceptor.class);
|
||||||
listenerContainerFactory.setBatchInterceptor(springKafkaTelemetry.createBatchInterceptor());
|
listenerContainerFactory.setBatchInterceptor(
|
||||||
listenerContainerFactory.setRecordInterceptor(springKafkaTelemetry.createRecordInterceptor());
|
springKafkaTelemetry.createBatchInterceptor(batchInterceptor));
|
||||||
|
listenerContainerFactory.setRecordInterceptor(
|
||||||
|
springKafkaTelemetry.createRecordInterceptor(recordInterceptor));
|
||||||
|
|
||||||
return listenerContainerFactory;
|
return listenerContainerFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static <T> T readField(Object container, String filedName, Class<T> fieldType) {
|
||||||
|
try {
|
||||||
|
Field field = AbstractKafkaListenerContainerFactory.class.getDeclaredField(filedName);
|
||||||
|
field.setAccessible(true);
|
||||||
|
return fieldType.cast(field.get(container));
|
||||||
|
} catch (Exception exception) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,11 @@ package io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumen
|
||||||
import io.opentelemetry.api.OpenTelemetry;
|
import io.opentelemetry.api.OpenTelemetry;
|
||||||
import io.opentelemetry.instrumentation.kafkaclients.v2_6.KafkaTelemetry;
|
import io.opentelemetry.instrumentation.kafkaclients.v2_6.KafkaTelemetry;
|
||||||
import io.opentelemetry.instrumentation.spring.autoconfigure.internal.ConditionalOnEnabledInstrumentation;
|
import io.opentelemetry.instrumentation.spring.autoconfigure.internal.ConditionalOnEnabledInstrumentation;
|
||||||
|
import io.opentelemetry.instrumentation.spring.kafka.v2_7.SpringKafkaTelemetry;
|
||||||
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
|
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.boot.autoconfigure.kafka.DefaultKafkaProducerFactoryCustomizer;
|
import org.springframework.boot.autoconfigure.kafka.DefaultKafkaProducerFactoryCustomizer;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
@ -33,13 +35,29 @@ public class KafkaInstrumentationAutoConfiguration {
|
||||||
return producerFactory -> producerFactory.addPostProcessor(kafkaTelemetry::wrap);
|
return producerFactory -> producerFactory.addPostProcessor(kafkaTelemetry::wrap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
static SpringKafkaTelemetry getTelemetry(
|
||||||
|
ObjectProvider<OpenTelemetry> openTelemetryProvider,
|
||||||
|
ObjectProvider<ConfigProperties> configPropertiesProvider) {
|
||||||
|
return SpringKafkaTelemetry.builder(openTelemetryProvider.getObject())
|
||||||
|
.setCaptureExperimentalSpanAttributes(
|
||||||
|
configPropertiesProvider
|
||||||
|
.getObject()
|
||||||
|
.getBoolean("otel.instrumentation.kafka.experimental-span-attributes", false))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
// static to avoid "is not eligible for getting processed by all BeanPostProcessors" warning
|
// static to avoid "is not eligible for getting processed by all BeanPostProcessors" warning
|
||||||
@Bean
|
@Bean
|
||||||
|
@ConditionalOnProperty(
|
||||||
|
name = "otel.instrumentation.kafka.autoconfigure-interceptor",
|
||||||
|
havingValue = "true",
|
||||||
|
matchIfMissing = true)
|
||||||
static ConcurrentKafkaListenerContainerFactoryPostProcessor
|
static ConcurrentKafkaListenerContainerFactoryPostProcessor
|
||||||
otelKafkaListenerContainerFactoryBeanPostProcessor(
|
otelKafkaListenerContainerFactoryBeanPostProcessor(
|
||||||
ObjectProvider<OpenTelemetry> openTelemetryProvider,
|
ObjectProvider<OpenTelemetry> openTelemetryProvider,
|
||||||
ObjectProvider<ConfigProperties> configPropertiesProvider) {
|
ObjectProvider<ConfigProperties> configPropertiesProvider) {
|
||||||
return new ConcurrentKafkaListenerContainerFactoryPostProcessor(
|
return new ConcurrentKafkaListenerContainerFactoryPostProcessor(
|
||||||
openTelemetryProvider, configPropertiesProvider);
|
() -> getTelemetry(openTelemetryProvider, configPropertiesProvider));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -357,6 +357,12 @@
|
||||||
"description": "Enable the capture of experimental Kafka span attributes.",
|
"description": "Enable the capture of experimental Kafka span attributes.",
|
||||||
"defaultValue": false
|
"defaultValue": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "otel.instrumentation.kafka.autoconfigure-interceptor",
|
||||||
|
"type": "java.lang.Boolean",
|
||||||
|
"description": "Enable automatic configuration of tracing interceptors on <code>ConcurrentKafkaListenerContainerFactory</code> using a <code>BeanPostProcessor</code>. You may disable this if you wish to manually configure these interceptors.",
|
||||||
|
"defaultValue": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "otel.instrumentation.mongo.enabled",
|
"name": "otel.instrumentation.mongo.enabled",
|
||||||
"type": "java.lang.Boolean",
|
"type": "java.lang.Boolean",
|
||||||
|
|
Loading…
Reference in New Issue