@@ -514,14 +514,14 @@ private Duration determineSendTimeout(KafkaOperations<?, ?> template) {
514
514
}
515
515
516
516
private void enhanceHeaders (Headers kafkaHeaders , ConsumerRecord <?, ?> record , Exception exception ) {
517
- maybeAddOriginalHeaders (kafkaHeaders , record );
517
+ maybeAddOriginalHeaders (kafkaHeaders , record , exception );
518
518
Headers headers = this .headersFunction .apply (record , exception );
519
519
if (headers != null ) {
520
520
headers .forEach (kafkaHeaders ::add );
521
521
}
522
522
}
523
523
524
- private void maybeAddOriginalHeaders (Headers kafkaHeaders , ConsumerRecord <?, ?> record ) {
524
+ private void maybeAddOriginalHeaders (Headers kafkaHeaders , ConsumerRecord <?, ?> record , Exception ex ) {
525
525
maybeAddHeader (kafkaHeaders , this .headerNames .original .topicHeader ,
526
526
record .topic ().getBytes (StandardCharsets .UTF_8 ));
527
527
maybeAddHeader (kafkaHeaders , this .headerNames .original .partitionHeader ,
@@ -532,6 +532,11 @@ private void maybeAddOriginalHeaders(Headers kafkaHeaders, ConsumerRecord<?, ?>
532
532
ByteBuffer .allocate (Long .BYTES ).putLong (record .timestamp ()).array ());
533
533
maybeAddHeader (kafkaHeaders , this .headerNames .original .timestampTypeHeader ,
534
534
record .timestampType ().toString ().getBytes (StandardCharsets .UTF_8 ));
535
+ if (ex instanceof ListenerExecutionFailedException ) {
536
+ String consumerGroup = ((ListenerExecutionFailedException ) ex ).getGroupId ();
537
+ maybeAddHeader (kafkaHeaders , this .headerNames .original .consumerGroup ,
538
+ consumerGroup .getBytes (StandardCharsets .UTF_8 ));
539
+ }
535
540
}
536
541
537
542
private void maybeAddHeader (Headers kafkaHeaders , String header , byte [] value ) {
@@ -540,11 +545,14 @@ private void maybeAddHeader(Headers kafkaHeaders, String header, byte[] value) {
540
545
}
541
546
}
542
547
543
- void addExceptionInfoHeaders (Headers kafkaHeaders , Exception exception ,
544
- boolean isKey ) {
548
+ void addExceptionInfoHeaders (Headers kafkaHeaders , Exception exception , boolean isKey ) {
545
549
kafkaHeaders .add (new RecordHeader (isKey ? this .headerNames .exceptionInfo .keyExceptionFqcn
546
550
: this .headerNames .exceptionInfo .exceptionFqcn ,
547
551
exception .getClass ().getName ().getBytes (StandardCharsets .UTF_8 )));
552
+ if (!isKey && exception .getCause () != null ) {
553
+ kafkaHeaders .add (new RecordHeader (this .headerNames .exceptionInfo .exceptionCauseFqcn ,
554
+ exception .getCause ().getClass ().getName ().getBytes (StandardCharsets .UTF_8 )));
555
+ }
548
556
String message = exception .getMessage ();
549
557
if (message != null ) {
550
558
kafkaHeaders .add (new RecordHeader (isKey
@@ -579,9 +587,11 @@ protected HeaderNames getHeaderNames() {
579
587
.timestampTypeHeader (KafkaHeaders .DLT_ORIGINAL_TIMESTAMP_TYPE )
580
588
.topicHeader (KafkaHeaders .DLT_ORIGINAL_TOPIC )
581
589
.partitionHeader (KafkaHeaders .DLT_ORIGINAL_PARTITION )
590
+ .consumerGroupHeader (KafkaHeaders .DLT_ORIGINAL_CONSUMER_GROUP )
582
591
.exception ()
583
592
.keyExceptionFqcn (KafkaHeaders .DLT_KEY_EXCEPTION_FQCN )
584
593
.exceptionFqcn (KafkaHeaders .DLT_EXCEPTION_FQCN )
594
+ .exceptionCauseFqcn (KafkaHeaders .DLT_EXCEPTION_CAUSE_FQCN )
585
595
.keyExceptionMessage (KafkaHeaders .DLT_KEY_EXCEPTION_MESSAGE )
586
596
.exceptionMessage (KafkaHeaders .DLT_EXCEPTION_MESSAGE )
587
597
.keyExceptionStacktrace (KafkaHeaders .DLT_KEY_EXCEPTION_STACKTRACE )
@@ -605,50 +615,67 @@ public static class HeaderNames {
605
615
}
606
616
607
617
static class Original {
608
- private final String offsetHeader ;
609
- private final String timestampHeader ;
610
- private final String timestampTypeHeader ;
611
- private final String topicHeader ;
612
- private final String partitionHeader ;
618
+
619
+ final String offsetHeader ;
620
+
621
+ final String timestampHeader ;
622
+
623
+ final String timestampTypeHeader ;
624
+
625
+ final String topicHeader ;
626
+
627
+ final String partitionHeader ;
628
+
629
+ final String consumerGroup ;
613
630
614
631
Original (String offsetHeader ,
615
632
String timestampHeader ,
616
633
String timestampTypeHeader ,
617
634
String topicHeader ,
618
- String partitionHeader ) {
635
+ String partitionHeader ,
636
+ String consumerGroup ) {
619
637
this .offsetHeader = offsetHeader ;
620
638
this .timestampHeader = timestampHeader ;
621
639
this .timestampTypeHeader = timestampTypeHeader ;
622
640
this .topicHeader = topicHeader ;
623
641
this .partitionHeader = partitionHeader ;
642
+ this .consumerGroup = consumerGroup ;
624
643
}
625
644
}
626
645
627
646
static class ExceptionInfo {
628
647
629
- private final String keyExceptionFqcn ;
630
- private final String exceptionFqcn ;
631
- private final String keyExceptionMessage ;
632
- private final String exceptionMessage ;
633
- private final String keyExceptionStacktrace ;
634
- private final String exceptionStacktrace ;
648
+ final String keyExceptionFqcn ;
649
+
650
+ final String exceptionFqcn ;
651
+
652
+ final String exceptionCauseFqcn ;
653
+
654
+ final String keyExceptionMessage ;
655
+
656
+ final String exceptionMessage ;
657
+
658
+ final String keyExceptionStacktrace ;
659
+
660
+ final String exceptionStacktrace ;
635
661
636
662
ExceptionInfo (String keyExceptionFqcn ,
637
- String exceptionFqcn ,
638
- String keyExceptionMessage ,
639
- String exceptionMessage ,
640
- String keyExceptionStacktrace ,
641
- String exceptionStacktrace ) {
663
+ String exceptionFqcn ,
664
+ String exceptionCauseFqcn ,
665
+ String keyExceptionMessage ,
666
+ String exceptionMessage ,
667
+ String keyExceptionStacktrace ,
668
+ String exceptionStacktrace ) {
642
669
this .keyExceptionFqcn = keyExceptionFqcn ;
643
670
this .exceptionFqcn = exceptionFqcn ;
671
+ this .exceptionCauseFqcn = exceptionCauseFqcn ;
644
672
this .keyExceptionMessage = keyExceptionMessage ;
645
673
this .exceptionMessage = exceptionMessage ;
646
674
this .keyExceptionStacktrace = keyExceptionStacktrace ;
647
675
this .exceptionStacktrace = exceptionStacktrace ;
648
676
}
649
677
}
650
678
651
-
652
679
/**
653
680
* Provides a convenient API for creating
654
681
* {@link DeadLetterPublishingRecoverer.HeaderNames}.
@@ -685,6 +712,8 @@ public class Original {
685
712
686
713
private String partitionHeader ;
687
714
715
+ private String consumerGroupHeader ;
716
+
688
717
/**
689
718
* Sets the name of the header that will be used to store the offset
690
719
* of the original record.
@@ -745,6 +774,18 @@ public Builder.Original partitionHeader(String partitionHeader) {
745
774
return this ;
746
775
}
747
776
777
+ /**
778
+ * Sets the name of the header that will be used to store the consumer
779
+ * group that failed to consume the original record.
780
+ * @param consumerGroup the consumer group header name.
781
+ * @return the Original builder instance
782
+ * @since 2.8
783
+ */
784
+ public Builder .Original consumerGroupHeader (String consumerGroupHeader ) {
785
+ this .consumerGroupHeader = consumerGroupHeader ;
786
+ return this ;
787
+ }
788
+
748
789
/**
749
790
* Returns the exception builder.
750
791
* @return the exception builder.
@@ -760,16 +801,18 @@ public ExceptionInfo exception() {
760
801
* @since 2.7
761
802
*/
762
803
private DeadLetterPublishingRecoverer .HeaderNames .Original build () {
763
- Assert .notNull (this .offsetHeader , "offsetHeader header cannot be null" );
764
- Assert .notNull (this .timestampHeader , "timestampHeader header cannot be null" );
765
- Assert .notNull (this .timestampTypeHeader , "timestampTypeHeader header cannot be null" );
766
- Assert .notNull (this .topicHeader , "topicHeader header cannot be null" );
767
- Assert .notNull (this .partitionHeader , "partitionHeader header cannot be null" );
804
+ Assert .notNull (this .offsetHeader , "offsetHeader cannot be null" );
805
+ Assert .notNull (this .timestampHeader , "timestampHeader cannot be null" );
806
+ Assert .notNull (this .timestampTypeHeader , "timestampTypeHeader cannot be null" );
807
+ Assert .notNull (this .topicHeader , "topicHeader cannot be null" );
808
+ Assert .notNull (this .partitionHeader , "partitionHeader cannot be null" );
809
+ Assert .notNull (this .consumerGroupHeader , "consumerGroupHeader cannot be null" );
768
810
return new DeadLetterPublishingRecoverer .HeaderNames .Original (this .offsetHeader ,
769
811
this .timestampHeader ,
770
812
this .timestampTypeHeader ,
771
813
this .topicHeader ,
772
- this .partitionHeader );
814
+ this .partitionHeader ,
815
+ this .consumerGroupHeader );
773
816
}
774
817
}
775
818
@@ -785,6 +828,8 @@ public class ExceptionInfo {
785
828
786
829
private String exceptionFqcn ;
787
830
831
+ private String exceptionCauseFqcn ;
832
+
788
833
private String keyExceptionMessage ;
789
834
790
835
private String exceptionMessage ;
@@ -817,6 +862,17 @@ public ExceptionInfo exceptionFqcn(String exceptionFqcn) {
817
862
return this ;
818
863
}
819
864
865
+ /**
866
+ * Sets the name of the header that will be used to store the exceptionCauseFqcn
867
+ * of the original record.
868
+ * @param exceptionFqcn the exceptionFqcn header name.
869
+ * @return the Exception builder instance
870
+ * @since 2.8
871
+ */
872
+ public ExceptionInfo exceptionCauseFqcn (String exceptionCauseFqcn ) {
873
+ this .exceptionCauseFqcn = exceptionCauseFqcn ;
874
+ return this ;
875
+ }
820
876
/**
821
877
* Sets the name of the header that will be used to store the keyExceptionMessage
822
878
* of the original record.
@@ -880,6 +936,7 @@ public DeadLetterPublishingRecoverer.HeaderNames build() {
880
936
return new DeadLetterPublishingRecoverer .HeaderNames (Builder .this .original .build (),
881
937
new HeaderNames .ExceptionInfo (this .keyExceptionFqcn ,
882
938
this .exceptionFqcn ,
939
+ this .exceptionCauseFqcn ,
883
940
this .keyExceptionMessage ,
884
941
this .exceptionMessage ,
885
942
this .keyExceptionStacktrace ,
0 commit comments