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 ;
80
81
import org .springframework .kafka .core .ProducerFactory ;
81
82
import org .springframework .kafka .listener .MessageListenerContainer ;
82
83
import org .springframework .kafka .listener .RecordInterceptor ;
84
+ import org .springframework .kafka .requestreply .ReplyingKafkaTemplate ;
83
85
import org .springframework .kafka .support .ProducerListener ;
84
86
import org .springframework .kafka .support .micrometer .KafkaListenerObservation .DefaultKafkaListenerObservationConvention ;
85
87
import org .springframework .kafka .support .micrometer .KafkaTemplateObservation .DefaultKafkaTemplateObservationConvention ;
86
88
import org .springframework .kafka .test .EmbeddedKafkaBroker ;
87
89
import org .springframework .kafka .test .context .EmbeddedKafka ;
88
90
import org .springframework .kafka .test .utils .KafkaTestUtils ;
89
- import org .springframework .lang . Nullable ;
91
+ import org .springframework .messaging . handler . annotation . SendTo ;
90
92
import org .springframework .test .annotation .DirtiesContext ;
91
93
import org .springframework .test .context .junit .jupiter .SpringJUnitConfig ;
92
94
import org .springframework .util .StringUtils ;
102
104
* @author Wang Zhiyang
103
105
* @author Christian Mergenthaler
104
106
* @author Soby Chacko
107
+ * @author Francois Rosiere
105
108
*
106
109
* @since 3.0
107
110
*/
108
111
@ SpringJUnitConfig
109
112
@ EmbeddedKafka (topics = {ObservationTests .OBSERVATION_TEST_1 , ObservationTests .OBSERVATION_TEST_2 ,
110
- ObservationTests .OBSERVATION_TEST_3 , ObservationTests .OBSERVATION_RUNTIME_EXCEPTION ,
111
- ObservationTests .OBSERVATION_ERROR , ObservationTests .OBSERVATION_TRACEPARENT_DUPLICATE }, partitions = 1 )
113
+ ObservationTests .OBSERVATION_TEST_3 , ObservationTests .OBSERVATION_TEST_4 , ObservationTests .OBSERVATION_REPLY ,
114
+ ObservationTests .OBSERVATION_RUNTIME_EXCEPTION , ObservationTests .OBSERVATION_ERROR ,
115
+ ObservationTests .OBSERVATION_TRACEPARENT_DUPLICATE }, partitions = 1 )
112
116
@ DirtiesContext
113
117
public class ObservationTests {
114
118
@@ -118,6 +122,10 @@ public class ObservationTests {
118
122
119
123
public final static String OBSERVATION_TEST_3 = "observation.testT3" ;
120
124
125
+ public final static String OBSERVATION_TEST_4 = "observation.testT4" ;
126
+
127
+ public final static String OBSERVATION_REPLY = "observation.reply" ;
128
+
121
129
public final static String OBSERVATION_RUNTIME_EXCEPTION = "observation.runtime-exception" ;
122
130
123
131
public final static String OBSERVATION_ERROR = "observation.error.sync" ;
@@ -513,6 +521,19 @@ public void onSuccess(ProducerRecord<Integer, String> producerRecord, RecordMeta
513
521
tracer .getSpans ().clear ();
514
522
}
515
523
524
+ @ Test
525
+ void testReplyingKafkaTemplateObservation (
526
+ @ Autowired ReplyingKafkaTemplate <Integer , String , String > template ,
527
+ @ Autowired ObservationRegistry observationRegistry ) {
528
+ assertThat (template .sendAndReceive (new ProducerRecord <>(OBSERVATION_TEST_4 , "test" ))
529
+ // the current observation must be retrieved from the consumer thread of the reply
530
+ .thenApply (replyRecord -> observationRegistry .getCurrentObservation ().getContext ()))
531
+ .succeedsWithin (Duration .ofSeconds (30 ))
532
+ .isInstanceOf (KafkaRecordReceiverContext .class )
533
+ .extracting ("name" )
534
+ .isEqualTo ("spring.kafka.listener" );
535
+ }
536
+
516
537
@ Configuration
517
538
@ EnableKafka
518
539
public static class Config {
@@ -586,13 +607,22 @@ KafkaTemplate<Integer, String> reuseAdminBeanKafkaTemplate(
586
607
return template ;
587
608
}
588
609
610
+ @ Bean
611
+ ReplyingKafkaTemplate <Integer , String , String > replyingKafkaTemplate (ProducerFactory <Integer , String > pf , ConcurrentKafkaListenerContainerFactory <Integer , String > containerFactory ) {
612
+ ReplyingKafkaTemplate <Integer , String , String > kafkaTemplate = new ReplyingKafkaTemplate <>(pf , containerFactory .createContainer (OBSERVATION_REPLY ));
613
+ kafkaTemplate .setObservationEnabled (true );
614
+ return kafkaTemplate ;
615
+ }
616
+
589
617
@ Bean
590
618
ConcurrentKafkaListenerContainerFactory <Integer , String > kafkaListenerContainerFactory (
591
- ConsumerFactory <Integer , String > cf , ObservationRegistry observationRegistry ) {
619
+ ConsumerFactory <Integer , String > cf , ObservationRegistry observationRegistry ,
620
+ KafkaTemplate <Integer , String > kafkaTemplate ) {
592
621
593
622
ConcurrentKafkaListenerContainerFactory <Integer , String > factory =
594
623
new ConcurrentKafkaListenerContainerFactory <>();
595
624
factory .setConsumerFactory (cf );
625
+ factory .setReplyTemplate (kafkaTemplate );
596
626
factory .getContainerProperties ().setObservationEnabled (true );
597
627
factory .setContainerCustomizer (container -> {
598
628
if (container .getListenerId ().equals ("obs3" )) {
@@ -659,7 +689,7 @@ public List<String> fields() {
659
689
// This is called on the producer side when the message is being sent
660
690
// Normally we would pass information from tracing context - for tests we don't need to
661
691
@ Override
662
- public <C > void inject (TraceContext context , @ Nullable C carrier , Setter <C > setter ) {
692
+ public <C > void inject (TraceContext context , C carrier , Setter <C > setter ) {
663
693
setter .set (carrier , "foo" , "some foo value" );
664
694
setter .set (carrier , "bar" , "some bar value" );
665
695
@@ -723,6 +753,12 @@ void listen2(ConsumerRecord<?, ?> in) {
723
753
void listen3 (ConsumerRecord <Integer , String > in ) {
724
754
}
725
755
756
+ @ KafkaListener (id = "obsReply" , topics = OBSERVATION_TEST_4 )
757
+ @ SendTo // default REPLY_TOPIC header
758
+ public String replyListener (ConsumerRecord <Integer , String > in ) {
759
+ return in .value ().toUpperCase ();
760
+ }
761
+
726
762
}
727
763
728
764
public static class ExceptionListener {
0 commit comments