Skip to content

Commit 4493427

Browse files
committed
spring-projectsGH-2198: Switch from Timer to Observation
spring-projects#2198 Phase 1
1 parent 408623c commit 4493427

File tree

12 files changed

+437
-427
lines changed

12 files changed

+437
-427
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: 32 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -61,15 +61,21 @@
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+
import io.micrometer.observation.ObservationRegistry;
78+
7379

7480
/**
7581
* A template for executing high-level operations. When used with a
@@ -106,9 +112,9 @@ public class KafkaTemplate<K, V> implements KafkaOperations<K, V>, ApplicationCo
106112

107113
private final Map<String, String> micrometerTags = new HashMap<>();
108114

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

111-
private ApplicationContext applicationContext;
117+
private String beanName = "kafkaTemplate";
112118

113119
private RecordMessageConverter messageConverter = new MessagingMessageConverter();
114120

@@ -126,11 +132,11 @@ public class KafkaTemplate<K, V> implements KafkaOperations<K, V>, ApplicationCo
126132

127133
private ConsumerFactory<K, V> consumerFactory;
128134

129-
private volatile boolean micrometerEnabled = true;
135+
private ProducerInterceptor<K, V> producerInterceptor;
130136

131-
private volatile MicrometerHolder micrometerHolder;
137+
private TagsProvider<?> tagsProvider = KafkaMetrics.templateTagsProvider(this.micrometerTags);
132138

133-
private ProducerInterceptor<K, V> producerInterceptor;
139+
private ObservationRegistry observationRegistry;
134140

135141
/**
136142
* Create an instance using the supplied producer factory and autoFlush false.
@@ -197,7 +203,6 @@ public KafkaTemplate(ProducerFactory<K, V> producerFactory, boolean autoFlush,
197203

198204
Assert.notNull(producerFactory, "'producerFactory' cannot be null");
199205
this.autoFlush = autoFlush;
200-
this.micrometerEnabled = KafkaUtils.MICROMETER_PRESENT;
201206
this.customProducerFactory = configOverrides != null && configOverrides.size() > 0;
202207
if (this.customProducerFactory) {
203208
this.producerFactory = producerFactory.copyWithConfigurationOverride(configOverrides);
@@ -211,11 +216,12 @@ public KafkaTemplate(ProducerFactory<K, V> producerFactory, boolean autoFlush,
211216
@Override
212217
public void setBeanName(String name) {
213218
this.beanName = name;
219+
this.observationContext.put(KafkaTemplateObservation.TemplateLowCardinalityTags.BEAN_NAME.getKey(), name);
214220
}
215221

216222
@Override
217223
public void setApplicationContext(ApplicationContext applicationContext) {
218-
this.applicationContext = applicationContext;
224+
this.observationRegistry = KafkaMetrics.getRegistry(applicationContext);
219225
if (this.customProducerFactory) {
220226
((DefaultKafkaProducerFactory<K, V>) this.producerFactory).setApplicationContext(applicationContext);
221227
}
@@ -327,9 +333,10 @@ public boolean isAllowNonTransactional() {
327333
* Set to false to disable micrometer timers, if micrometer is on the class path.
328334
* @param micrometerEnabled false to disable.
329335
* @since 2.5
336+
* @deprecated this is no longer used.
330337
*/
338+
@Deprecated
331339
public void setMicrometerEnabled(boolean micrometerEnabled) {
332-
this.micrometerEnabled = micrometerEnabled;
333340
}
334341

335342
/**
@@ -338,8 +345,9 @@ public void setMicrometerEnabled(boolean micrometerEnabled) {
338345
* @since 2.5
339346
*/
340347
public void setMicrometerTags(Map<String, String> tags) {
341-
if (tags != null) {
348+
if (!ObjectUtils.isEmpty(tags)) {
342349
this.micrometerTags.putAll(tags);
350+
this.tagsProvider = KafkaMetrics.templateTagsProvider(this.micrometerTags);
343351
}
344352
}
345353

@@ -625,18 +633,19 @@ protected ListenableFuture<SendResult<K, V>> doSend(final ProducerRecord<K, V> p
625633
final Producer<K, V> producer = getTheProducer(producerRecord.topic());
626634
this.logger.trace(() -> "Sending: " + KafkaUtils.format(producerRecord));
627635
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();
636+
Observation observation = null;
637+
if (this.observationRegistry != null) {
638+
observation = Observation
639+
.createNotStarted(KafkaTemplateObservation.TEMPLATE_OBSERVATION.getName(),
640+
this.observationContext, this.observationRegistry)
641+
.tagsProvider(this.tagsProvider)
642+
.start();
634643
}
635644
if (this.producerInterceptor != null) {
636645
this.producerInterceptor.onSend(producerRecord);
637646
}
638647
Future<RecordMetadata> sendFuture =
639-
producer.send(producerRecord, buildCallback(producerRecord, producer, future, sample));
648+
producer.send(producerRecord, buildCallback(producerRecord, producer, future, observation));
640649
// May be an immediate failure
641650
if (sendFuture.isDone()) {
642651
try {
@@ -658,7 +667,7 @@ protected ListenableFuture<SendResult<K, V>> doSend(final ProducerRecord<K, V> p
658667
}
659668

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

663672
return (metadata, exception) -> {
664673
try {
@@ -671,9 +680,6 @@ private Callback buildCallback(final ProducerRecord<K, V> producerRecord, final
671680
}
672681
try {
673682
if (exception == null) {
674-
if (sample != null) {
675-
this.micrometerHolder.success(sample);
676-
}
677683
future.set(new SendResult<>(producerRecord, metadata));
678684
if (KafkaTemplate.this.producerListener != null) {
679685
KafkaTemplate.this.producerListener.onSuccess(producerRecord, metadata);
@@ -682,8 +688,8 @@ private Callback buildCallback(final ProducerRecord<K, V> producerRecord, final
682688
+ ", metadata: " + metadata);
683689
}
684690
else {
685-
if (sample != null) {
686-
this.micrometerHolder.failure(sample, exception.getClass().getSimpleName());
691+
if (observation != null) {
692+
observation.error(exception);
687693
}
688694
future.setException(new KafkaProducerException(producerRecord, "Failed to send", exception));
689695
if (KafkaTemplate.this.producerListener != null) {
@@ -694,6 +700,9 @@ private Callback buildCallback(final ProducerRecord<K, V> producerRecord, final
694700
}
695701
}
696702
finally {
703+
if (observation != null) {
704+
observation.stop();
705+
}
697706
if (!KafkaTemplate.this.transactional) {
698707
closeProducer(producer, false);
699708
}
@@ -753,27 +762,8 @@ else if (topic == null) {
753762
}
754763
}
755764

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-
772765
@Override
773766
public void destroy() {
774-
if (this.micrometerHolder != null) {
775-
this.micrometerHolder.destroy();
776-
}
777767
if (this.customProducerFactory) {
778768
((DefaultKafkaProducerFactory<K, V>) this.producerFactory).destroy();
779769
}

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)