Skip to content

Commit 7fa45ca

Browse files
committed
spring-projectsGH-2198: Switch from Timer to Observation
spring-projects#2198 Phase 1
1 parent 448871a commit 7fa45ca

File tree

12 files changed

+365
-432
lines changed

12 files changed

+365
-432
lines changed

build.gradle

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ ext {
6666
junitJupiterVersion = '5.8.2'
6767
kafkaVersion = '3.1.0'
6868
log4jVersion = '2.17.2'
69-
micrometerVersion = '2.0.0-M3'
69+
micrometerVersion = '2.0.0-SNAPSHOT'
70+
micrometerTracingVersion = '1.0.0-SNAPSHOT'
7071
mockitoVersion = '4.0.0'
7172
reactorVersion = '2020.0.17'
7273
scalaVersion = '2.13'
@@ -104,6 +105,8 @@ allprojects {
104105
mavenBom "org.springframework:spring-framework-bom:$springVersion"
105106
mavenBom "io.projectreactor:reactor-bom:$reactorVersion"
106107
mavenBom "org.springframework.data:spring-data-bom:$springDataVersion"
108+
mavenBom "io.micrometer:micrometer-bom:$micrometerVersion"
109+
mavenBom "io.micrometer:micrometer-tracing-bom:$micrometerTracingVersion"
107110
}
108111
}
109112

@@ -319,7 +322,6 @@ project ('spring-kafka') {
319322
}
320323
api "org.apache.kafka:kafka-clients:$kafkaVersion"
321324
optionalApi "org.apache.kafka:kafka-streams:$kafkaVersion"
322-
323325
optionalApi 'com.fasterxml.jackson.core:jackson-core'
324326
optionalApi 'com.fasterxml.jackson.core:jackson-databind'
325327
optionalApi 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8'
@@ -338,13 +340,16 @@ project ('spring-kafka') {
338340

339341
optionalApi 'io.projectreactor:reactor-core'
340342
optionalApi 'io.projectreactor.kafka:reactor-kafka'
341-
optionalApi "io.micrometer:micrometer-core:$micrometerVersion"
342-
optionalApi "io.micrometer:micrometer-binders:$micrometerVersion"
343+
optionalApi "io.micrometer:micrometer-binders"
344+
optionalApi 'io.micrometer:micrometer-tracing-api'
343345

344346
testImplementation project (':spring-kafka-test')
345347
testImplementation 'io.projectreactor:reactor-test'
346348
testImplementation "org.mockito:mockito-junit-jupiter:$mockitoVersion"
347349
testImplementation "org.hibernate.validator:hibernate-validator:$hibernateValidationVersion"
350+
testImplementation 'io.micrometer:micrometer-tracing-bridge-brave'
351+
testImplementation("io.micrometer:micrometer-tracing-test")
352+
testImplementation("io.micrometer:micrometer-tracing-integration-test")
348353
}
349354
}
350355

spring-kafka/src/main/java/org/springframework/kafka/core/KafkaTemplate.java

Lines changed: 24 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -61,15 +61,20 @@
6161
import org.springframework.kafka.support.TopicPartitionOffset;
6262
import org.springframework.kafka.support.converter.MessagingMessageConverter;
6363
import org.springframework.kafka.support.converter.RecordMessageConverter;
64-
import org.springframework.kafka.support.micrometer.MicrometerHolder;
64+
import org.springframework.kafka.support.micrometer.KafkaMetrics;
65+
import org.springframework.kafka.support.micrometer.KafkaTemplateObservation;
6566
import org.springframework.lang.Nullable;
6667
import org.springframework.messaging.Message;
6768
import org.springframework.messaging.converter.SmartMessageConverter;
6869
import org.springframework.transaction.support.TransactionSynchronizationManager;
6970
import org.springframework.util.Assert;
71+
import org.springframework.util.ObjectUtils;
7072
import org.springframework.util.concurrent.ListenableFuture;
7173
import org.springframework.util.concurrent.SettableListenableFuture;
7274

75+
import io.micrometer.observation.Observation;
76+
import io.micrometer.observation.Observation.TagsProvider;
77+
7378

7479
/**
7580
* A template for executing high-level operations. When used with a
@@ -106,9 +111,9 @@ public class KafkaTemplate<K, V> implements KafkaOperations<K, V>, ApplicationCo
106111

107112
private final Map<String, String> micrometerTags = new HashMap<>();
108113

109-
private String beanName = "kafkaTemplate";
114+
private final Observation.Context observationContext = new Observation.Context();
110115

111-
private ApplicationContext applicationContext;
116+
private String beanName = "kafkaTemplate";
112117

113118
private RecordMessageConverter messageConverter = new MessagingMessageConverter();
114119

@@ -126,12 +131,10 @@ public class KafkaTemplate<K, V> implements KafkaOperations<K, V>, ApplicationCo
126131

127132
private ConsumerFactory<K, V> consumerFactory;
128133

129-
private volatile boolean micrometerEnabled = true;
130-
131-
private volatile MicrometerHolder micrometerHolder;
132-
133134
private ProducerInterceptor<K, V> producerInterceptor;
134135

136+
private TagsProvider<?> tagsProvider = KafkaMetrics.templateTagsProvider(this.micrometerTags);
137+
135138
/**
136139
* Create an instance using the supplied producer factory and autoFlush false.
137140
* @param producerFactory the producer factory.
@@ -197,7 +200,6 @@ public KafkaTemplate(ProducerFactory<K, V> producerFactory, boolean autoFlush,
197200

198201
Assert.notNull(producerFactory, "'producerFactory' cannot be null");
199202
this.autoFlush = autoFlush;
200-
this.micrometerEnabled = KafkaUtils.MICROMETER_PRESENT;
201203
this.customProducerFactory = configOverrides != null && configOverrides.size() > 0;
202204
if (this.customProducerFactory) {
203205
this.producerFactory = producerFactory.copyWithConfigurationOverride(configOverrides);
@@ -211,11 +213,11 @@ public KafkaTemplate(ProducerFactory<K, V> producerFactory, boolean autoFlush,
211213
@Override
212214
public void setBeanName(String name) {
213215
this.beanName = name;
216+
this.observationContext.put(KafkaTemplateObservation.TemplateLowCardinalityTags.BEAN_NAME.getKey(), name);
214217
}
215218

216219
@Override
217220
public void setApplicationContext(ApplicationContext applicationContext) {
218-
this.applicationContext = applicationContext;
219221
if (this.customProducerFactory) {
220222
((DefaultKafkaProducerFactory<K, V>) this.producerFactory).setApplicationContext(applicationContext);
221223
}
@@ -327,9 +329,10 @@ public boolean isAllowNonTransactional() {
327329
* Set to false to disable micrometer timers, if micrometer is on the class path.
328330
* @param micrometerEnabled false to disable.
329331
* @since 2.5
332+
* @deprecated this is no longer used.
330333
*/
334+
@Deprecated
331335
public void setMicrometerEnabled(boolean micrometerEnabled) {
332-
this.micrometerEnabled = micrometerEnabled;
333336
}
334337

335338
/**
@@ -338,8 +341,9 @@ public void setMicrometerEnabled(boolean micrometerEnabled) {
338341
* @since 2.5
339342
*/
340343
public void setMicrometerTags(Map<String, String> tags) {
341-
if (tags != null) {
344+
if (!ObjectUtils.isEmpty(tags)) {
342345
this.micrometerTags.putAll(tags);
346+
this.tagsProvider = KafkaMetrics.templateTagsProvider(this.micrometerTags);
343347
}
344348
}
345349

@@ -625,18 +629,16 @@ protected ListenableFuture<SendResult<K, V>> doSend(final ProducerRecord<K, V> p
625629
final Producer<K, V> producer = getTheProducer(producerRecord.topic());
626630
this.logger.trace(() -> "Sending: " + KafkaUtils.format(producerRecord));
627631
final SettableListenableFuture<SendResult<K, V>> future = new SettableListenableFuture<>();
628-
Object sample = null;
629-
if (this.micrometerEnabled && this.micrometerHolder == null) {
630-
this.micrometerHolder = obtainMicrometerHolder();
631-
}
632-
if (this.micrometerHolder != null) {
633-
sample = this.micrometerHolder.start();
634-
}
632+
Observation observation = Observation
633+
.createNotStarted(KafkaTemplateObservation.TEMPLATE_OBSERVATION.getName(),
634+
this.observationContext, KafkaMetrics.OBSERVATION_REGISTRY)
635+
.tagsProvider(this.tagsProvider)
636+
.start();
635637
if (this.producerInterceptor != null) {
636638
this.producerInterceptor.onSend(producerRecord);
637639
}
638640
Future<RecordMetadata> sendFuture =
639-
producer.send(producerRecord, buildCallback(producerRecord, producer, future, sample));
641+
producer.send(producerRecord, buildCallback(producerRecord, producer, future, observation));
640642
// May be an immediate failure
641643
if (sendFuture.isDone()) {
642644
try {
@@ -658,7 +660,7 @@ protected ListenableFuture<SendResult<K, V>> doSend(final ProducerRecord<K, V> p
658660
}
659661

660662
private Callback buildCallback(final ProducerRecord<K, V> producerRecord, final Producer<K, V> producer,
661-
final SettableListenableFuture<SendResult<K, V>> future, @Nullable Object sample) {
663+
final SettableListenableFuture<SendResult<K, V>> future, Observation observation) {
662664

663665
return (metadata, exception) -> {
664666
try {
@@ -671,9 +673,6 @@ private Callback buildCallback(final ProducerRecord<K, V> producerRecord, final
671673
}
672674
try {
673675
if (exception == null) {
674-
if (sample != null) {
675-
this.micrometerHolder.success(sample);
676-
}
677676
future.set(new SendResult<>(producerRecord, metadata));
678677
if (KafkaTemplate.this.producerListener != null) {
679678
KafkaTemplate.this.producerListener.onSuccess(producerRecord, metadata);
@@ -682,9 +681,7 @@ private Callback buildCallback(final ProducerRecord<K, V> producerRecord, final
682681
+ ", metadata: " + metadata);
683682
}
684683
else {
685-
if (sample != null) {
686-
this.micrometerHolder.failure(sample, exception.getClass().getSimpleName());
687-
}
684+
observation.error(exception);
688685
future.setException(new KafkaProducerException(producerRecord, "Failed to send", exception));
689686
if (KafkaTemplate.this.producerListener != null) {
690687
KafkaTemplate.this.producerListener.onError(producerRecord, metadata, exception);
@@ -694,6 +691,7 @@ private Callback buildCallback(final ProducerRecord<K, V> producerRecord, final
694691
}
695692
}
696693
finally {
694+
observation.stop();
697695
if (!KafkaTemplate.this.transactional) {
698696
closeProducer(producer, false);
699697
}
@@ -753,27 +751,8 @@ else if (topic == null) {
753751
}
754752
}
755753

756-
@Nullable
757-
private MicrometerHolder obtainMicrometerHolder() {
758-
MicrometerHolder holder = null;
759-
try {
760-
if (KafkaUtils.MICROMETER_PRESENT) {
761-
holder = new MicrometerHolder(this.applicationContext, this.beanName,
762-
"spring.kafka.template", "KafkaTemplate Timer",
763-
this.micrometerTags);
764-
}
765-
}
766-
catch (@SuppressWarnings("unused") IllegalStateException ex) {
767-
this.micrometerEnabled = false;
768-
}
769-
return holder;
770-
}
771-
772754
@Override
773755
public void destroy() {
774-
if (this.micrometerHolder != null) {
775-
this.micrometerHolder.destroy();
776-
}
777756
if (this.customProducerFactory) {
778757
((DefaultKafkaProducerFactory<K, V>) this.producerFactory).destroy();
779758
}

spring-kafka/src/main/java/org/springframework/kafka/listener/ContainerProperties.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -260,8 +260,6 @@ public enum EOSMode {
260260

261261
private long idleBetweenPolls;
262262

263-
private boolean micrometerEnabled = true;
264-
265263
private Duration consumerStartTimeout = DEFAULT_CONSUMER_START_TIMEOUT;
266264

267265
private Boolean subBatchPerPartition;
@@ -622,17 +620,19 @@ public long getIdleBetweenPolls() {
622620
return this.idleBetweenPolls;
623621
}
624622

623+
@Deprecated
625624
public boolean isMicrometerEnabled() {
626-
return this.micrometerEnabled;
625+
return true;
627626
}
628627

629628
/**
630629
* Set to false to disable the Micrometer listener timers. Default true.
631630
* @param micrometerEnabled false to disable.
632631
* @since 2.3
632+
* @deprecated this is no longer used.
633633
*/
634+
@Deprecated
634635
public void setMicrometerEnabled(boolean micrometerEnabled) {
635-
this.micrometerEnabled = micrometerEnabled;
636636
}
637637

638638
/**

0 commit comments

Comments
 (0)