17
17
package org .springframework .kafka .support .micrometer ;
18
18
19
19
import java .nio .charset .StandardCharsets ;
20
+ import java .time .Duration ;
20
21
import java .util .Arrays ;
21
22
import java .util .Deque ;
22
23
import java .util .List ;
76
77
import org .springframework .kafka .core .KafkaTemplate ;
77
78
import org .springframework .kafka .core .ProducerFactory ;
78
79
import org .springframework .kafka .listener .MessageListenerContainer ;
80
+ import org .springframework .kafka .requestreply .ReplyingKafkaTemplate ;
79
81
import org .springframework .kafka .support .ProducerListener ;
80
82
import org .springframework .kafka .support .micrometer .KafkaListenerObservation .DefaultKafkaListenerObservationConvention ;
81
83
import org .springframework .kafka .support .micrometer .KafkaTemplateObservation .DefaultKafkaTemplateObservationConvention ;
82
84
import org .springframework .kafka .test .EmbeddedKafkaBroker ;
83
85
import org .springframework .kafka .test .context .EmbeddedKafka ;
84
86
import org .springframework .kafka .test .utils .KafkaTestUtils ;
85
- import org .springframework .lang . Nullable ;
87
+ import org .springframework .messaging . handler . annotation . SendTo ;
86
88
import org .springframework .test .annotation .DirtiesContext ;
87
89
import org .springframework .test .context .junit .jupiter .SpringJUnitConfig ;
88
90
import org .springframework .util .StringUtils ;
98
100
* @author Wang Zhiyang
99
101
* @author Christian Mergenthaler
100
102
* @author Soby Chacko
103
+ * @author Francois Rosiere
101
104
*
102
105
* @since 3.0
103
106
*/
104
107
@ SpringJUnitConfig
105
108
@ EmbeddedKafka (topics = {ObservationTests .OBSERVATION_TEST_1 , ObservationTests .OBSERVATION_TEST_2 ,
106
- ObservationTests .OBSERVATION_TEST_3 , ObservationTests .OBSERVATION_RUNTIME_EXCEPTION ,
107
- ObservationTests .OBSERVATION_ERROR , ObservationTests .OBSERVATION_TRACEPARENT_DUPLICATE }, partitions = 1 )
109
+ ObservationTests .OBSERVATION_TEST_3 , ObservationTests .OBSERVATION_TEST_4 , ObservationTests .OBSERVATION_REPLY ,
110
+ ObservationTests .OBSERVATION_RUNTIME_EXCEPTION , ObservationTests .OBSERVATION_ERROR ,
111
+ ObservationTests .OBSERVATION_TRACEPARENT_DUPLICATE }, partitions = 1 )
108
112
@ DirtiesContext
109
113
public class ObservationTests {
110
114
@@ -114,6 +118,10 @@ public class ObservationTests {
114
118
115
119
public final static String OBSERVATION_TEST_3 = "observation.testT3" ;
116
120
121
+ public final static String OBSERVATION_TEST_4 = "observation.testT4" ;
122
+
123
+ public final static String OBSERVATION_REPLY = "observation.reply" ;
124
+
117
125
public final static String OBSERVATION_RUNTIME_EXCEPTION = "observation.runtime-exception" ;
118
126
119
127
public final static String OBSERVATION_ERROR = "observation.error" ;
@@ -356,7 +364,7 @@ private void assertThatAdmin(Object object, KafkaAdmin admin, String brokersStri
356
364
void observationRuntimeException (@ Autowired ExceptionListener listener , @ Autowired SimpleTracer tracer ,
357
365
@ Autowired @ Qualifier ("throwableTemplate" ) KafkaTemplate <Integer , String > runtimeExceptionTemplate ,
358
366
@ Autowired KafkaListenerEndpointRegistry endpointRegistry )
359
- throws ExecutionException , InterruptedException , TimeoutException {
367
+ throws ExecutionException , InterruptedException , TimeoutException {
360
368
361
369
runtimeExceptionTemplate .send (OBSERVATION_RUNTIME_EXCEPTION , "testRuntimeException" ).get (10 , TimeUnit .SECONDS );
362
370
assertThat (listener .latch4 .await (10 , TimeUnit .SECONDS )).isTrue ();
@@ -459,6 +467,19 @@ public void onSuccess(ProducerRecord<Integer, String> producerRecord, RecordMeta
459
467
tracer .getSpans ().clear ();
460
468
}
461
469
470
+ @ Test
471
+ void testReplyingKafkaTemplateObservation (
472
+ @ Autowired ReplyingKafkaTemplate <Integer , String , String > template ,
473
+ @ Autowired ObservationRegistry observationRegistry ) {
474
+ assertThat (template .sendAndReceive (new ProducerRecord <>(OBSERVATION_TEST_4 , "test" ))
475
+ // the current observation must be retrieved from the consumer thread of the reply
476
+ .thenApply (replyRecord -> observationRegistry .getCurrentObservation ().getContext ()))
477
+ .succeedsWithin (Duration .ofSeconds (30 ))
478
+ .isInstanceOf (KafkaRecordReceiverContext .class )
479
+ .extracting ("name" )
480
+ .isEqualTo ("spring.kafka.listener" );
481
+ }
482
+
462
483
@ Configuration
463
484
@ EnableKafka
464
485
public static class Config {
@@ -530,13 +551,22 @@ KafkaTemplate<Integer, String> reuseAdminBeanKafkaTemplate(
530
551
return template ;
531
552
}
532
553
554
+ @ Bean
555
+ ReplyingKafkaTemplate <Integer , String , String > replyingKafkaTemplate (ProducerFactory <Integer , String > pf , ConcurrentKafkaListenerContainerFactory <Integer , String > containerFactory ) {
556
+ ReplyingKafkaTemplate <Integer , String , String > kafkaTemplate = new ReplyingKafkaTemplate <>(pf , containerFactory .createContainer (OBSERVATION_REPLY ));
557
+ kafkaTemplate .setObservationEnabled (true );
558
+ return kafkaTemplate ;
559
+ }
560
+
533
561
@ Bean
534
562
ConcurrentKafkaListenerContainerFactory <Integer , String > kafkaListenerContainerFactory (
535
- ConsumerFactory <Integer , String > cf ) {
563
+ ConsumerFactory <Integer , String > cf , ObservationRegistry observationRegistry ,
564
+ KafkaTemplate <Integer , String > kafkaTemplate ) {
536
565
537
566
ConcurrentKafkaListenerContainerFactory <Integer , String > factory =
538
567
new ConcurrentKafkaListenerContainerFactory <>();
539
568
factory .setConsumerFactory (cf );
569
+ factory .setReplyTemplate (kafkaTemplate );
540
570
factory .getContainerProperties ().setObservationEnabled (true );
541
571
factory .setContainerCustomizer (container -> {
542
572
if (container .getListenerId ().equals ("obs3" )) {
@@ -585,7 +615,7 @@ public List<String> fields() {
585
615
// This is called on the producer side when the message is being sent
586
616
// Normally we would pass information from tracing context - for tests we don't need to
587
617
@ Override
588
- public <C > void inject (TraceContext context , @ Nullable C carrier , Setter <C > setter ) {
618
+ public <C > void inject (TraceContext context , C carrier , Setter <C > setter ) {
589
619
setter .set (carrier , "foo" , "some foo value" );
590
620
setter .set (carrier , "bar" , "some bar value" );
591
621
@@ -649,6 +679,12 @@ void listen2(ConsumerRecord<?, ?> in) {
649
679
void listen3 (ConsumerRecord <Integer , String > in ) {
650
680
}
651
681
682
+ @ KafkaListener (id = "obsReply" , topics = OBSERVATION_TEST_4 )
683
+ @ SendTo // default REPLY_TOPIC header
684
+ public String replyListener (ConsumerRecord <Integer , String > in ) {
685
+ return in .value ().toUpperCase ();
686
+ }
687
+
652
688
}
653
689
654
690
public static class ExceptionListener {
0 commit comments