@@ -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,13 @@ 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
+ if (consumerGroup != null ) {
538
+ maybeAddHeader (kafkaHeaders , this .headerNames .original .consumerGroup ,
539
+ consumerGroup .getBytes (StandardCharsets .UTF_8 ));
540
+ }
541
+ }
535
542
}
536
543
537
544
private void maybeAddHeader (Headers kafkaHeaders , String header , byte [] value ) {
@@ -540,11 +547,14 @@ private void maybeAddHeader(Headers kafkaHeaders, String header, byte[] value) {
540
547
}
541
548
}
542
549
543
- void addExceptionInfoHeaders (Headers kafkaHeaders , Exception exception ,
544
- boolean isKey ) {
550
+ void addExceptionInfoHeaders (Headers kafkaHeaders , Exception exception , boolean isKey ) {
545
551
kafkaHeaders .add (new RecordHeader (isKey ? this .headerNames .exceptionInfo .keyExceptionFqcn
546
552
: this .headerNames .exceptionInfo .exceptionFqcn ,
547
553
exception .getClass ().getName ().getBytes (StandardCharsets .UTF_8 )));
554
+ if (!isKey && exception .getCause () != null ) {
555
+ kafkaHeaders .add (new RecordHeader (this .headerNames .exceptionInfo .exceptionCauseFqcn ,
556
+ exception .getCause ().getClass ().getName ().getBytes (StandardCharsets .UTF_8 )));
557
+ }
548
558
String message = exception .getMessage ();
549
559
if (message != null ) {
550
560
kafkaHeaders .add (new RecordHeader (isKey
@@ -579,9 +589,11 @@ protected HeaderNames getHeaderNames() {
579
589
.timestampTypeHeader (KafkaHeaders .DLT_ORIGINAL_TIMESTAMP_TYPE )
580
590
.topicHeader (KafkaHeaders .DLT_ORIGINAL_TOPIC )
581
591
.partitionHeader (KafkaHeaders .DLT_ORIGINAL_PARTITION )
592
+ .consumerGroupHeader (KafkaHeaders .DLT_ORIGINAL_CONSUMER_GROUP )
582
593
.exception ()
583
594
.keyExceptionFqcn (KafkaHeaders .DLT_KEY_EXCEPTION_FQCN )
584
595
.exceptionFqcn (KafkaHeaders .DLT_EXCEPTION_FQCN )
596
+ .exceptionCauseFqcn (KafkaHeaders .DLT_EXCEPTION_CAUSE_FQCN )
585
597
.keyExceptionMessage (KafkaHeaders .DLT_KEY_EXCEPTION_MESSAGE )
586
598
.exceptionMessage (KafkaHeaders .DLT_EXCEPTION_MESSAGE )
587
599
.keyExceptionStacktrace (KafkaHeaders .DLT_KEY_EXCEPTION_STACKTRACE )
@@ -605,50 +617,67 @@ public static class HeaderNames {
605
617
}
606
618
607
619
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 ;
620
+
621
+ final String offsetHeader ;
622
+
623
+ final String timestampHeader ;
624
+
625
+ final String timestampTypeHeader ;
626
+
627
+ final String topicHeader ;
628
+
629
+ final String partitionHeader ;
630
+
631
+ final String consumerGroup ;
613
632
614
633
Original (String offsetHeader ,
615
634
String timestampHeader ,
616
635
String timestampTypeHeader ,
617
636
String topicHeader ,
618
- String partitionHeader ) {
637
+ String partitionHeader ,
638
+ String consumerGroup ) {
619
639
this .offsetHeader = offsetHeader ;
620
640
this .timestampHeader = timestampHeader ;
621
641
this .timestampTypeHeader = timestampTypeHeader ;
622
642
this .topicHeader = topicHeader ;
623
643
this .partitionHeader = partitionHeader ;
644
+ this .consumerGroup = consumerGroup ;
624
645
}
625
646
}
626
647
627
648
static class ExceptionInfo {
628
649
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 ;
650
+ final String keyExceptionFqcn ;
651
+
652
+ final String exceptionFqcn ;
653
+
654
+ final String exceptionCauseFqcn ;
655
+
656
+ final String keyExceptionMessage ;
657
+
658
+ final String exceptionMessage ;
659
+
660
+ final String keyExceptionStacktrace ;
661
+
662
+ final String exceptionStacktrace ;
635
663
636
664
ExceptionInfo (String keyExceptionFqcn ,
637
- String exceptionFqcn ,
638
- String keyExceptionMessage ,
639
- String exceptionMessage ,
640
- String keyExceptionStacktrace ,
641
- String exceptionStacktrace ) {
665
+ String exceptionFqcn ,
666
+ String exceptionCauseFqcn ,
667
+ String keyExceptionMessage ,
668
+ String exceptionMessage ,
669
+ String keyExceptionStacktrace ,
670
+ String exceptionStacktrace ) {
642
671
this .keyExceptionFqcn = keyExceptionFqcn ;
643
672
this .exceptionFqcn = exceptionFqcn ;
673
+ this .exceptionCauseFqcn = exceptionCauseFqcn ;
644
674
this .keyExceptionMessage = keyExceptionMessage ;
645
675
this .exceptionMessage = exceptionMessage ;
646
676
this .keyExceptionStacktrace = keyExceptionStacktrace ;
647
677
this .exceptionStacktrace = exceptionStacktrace ;
648
678
}
649
679
}
650
680
651
-
652
681
/**
653
682
* Provides a convenient API for creating
654
683
* {@link DeadLetterPublishingRecoverer.HeaderNames}.
@@ -685,6 +714,8 @@ public class Original {
685
714
686
715
private String partitionHeader ;
687
716
717
+ private String consumerGroupHeader ;
718
+
688
719
/**
689
720
* Sets the name of the header that will be used to store the offset
690
721
* of the original record.
@@ -745,6 +776,18 @@ public Builder.Original partitionHeader(String partitionHeader) {
745
776
return this ;
746
777
}
747
778
779
+ /**
780
+ * Sets the name of the header that will be used to store the consumer
781
+ * group that failed to consume the original record.
782
+ * @param consumerGroup the consumer group header name.
783
+ * @return the Original builder instance
784
+ * @since 2.8
785
+ */
786
+ public Builder .Original consumerGroupHeader (String consumerGroupHeader ) {
787
+ this .consumerGroupHeader = consumerGroupHeader ;
788
+ return this ;
789
+ }
790
+
748
791
/**
749
792
* Returns the exception builder.
750
793
* @return the exception builder.
@@ -760,16 +803,18 @@ public ExceptionInfo exception() {
760
803
* @since 2.7
761
804
*/
762
805
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" );
806
+ Assert .notNull (this .offsetHeader , "offsetHeader cannot be null" );
807
+ Assert .notNull (this .timestampHeader , "timestampHeader cannot be null" );
808
+ Assert .notNull (this .timestampTypeHeader , "timestampTypeHeader cannot be null" );
809
+ Assert .notNull (this .topicHeader , "topicHeader cannot be null" );
810
+ Assert .notNull (this .partitionHeader , "partitionHeader cannot be null" );
811
+ Assert .notNull (this .consumerGroupHeader , "consumerGroupHeader cannot be null" );
768
812
return new DeadLetterPublishingRecoverer .HeaderNames .Original (this .offsetHeader ,
769
813
this .timestampHeader ,
770
814
this .timestampTypeHeader ,
771
815
this .topicHeader ,
772
- this .partitionHeader );
816
+ this .partitionHeader ,
817
+ this .consumerGroupHeader );
773
818
}
774
819
}
775
820
@@ -785,6 +830,8 @@ public class ExceptionInfo {
785
830
786
831
private String exceptionFqcn ;
787
832
833
+ private String exceptionCauseFqcn ;
834
+
788
835
private String keyExceptionMessage ;
789
836
790
837
private String exceptionMessage ;
@@ -817,6 +864,17 @@ public ExceptionInfo exceptionFqcn(String exceptionFqcn) {
817
864
return this ;
818
865
}
819
866
867
+ /**
868
+ * Sets the name of the header that will be used to store the exceptionCauseFqcn
869
+ * of the original record.
870
+ * @param exceptionFqcn the exceptionFqcn header name.
871
+ * @return the Exception builder instance
872
+ * @since 2.8
873
+ */
874
+ public ExceptionInfo exceptionCauseFqcn (String exceptionCauseFqcn ) {
875
+ this .exceptionCauseFqcn = exceptionCauseFqcn ;
876
+ return this ;
877
+ }
820
878
/**
821
879
* Sets the name of the header that will be used to store the keyExceptionMessage
822
880
* of the original record.
@@ -873,13 +931,15 @@ public ExceptionInfo exceptionStacktrace(String exceptionStacktrace) {
873
931
public DeadLetterPublishingRecoverer .HeaderNames build () {
874
932
Assert .notNull (this .keyExceptionFqcn , "keyExceptionFqcn header cannot be null" );
875
933
Assert .notNull (this .exceptionFqcn , "exceptionFqcn header cannot be null" );
934
+ Assert .notNull (this .exceptionCauseFqcn , "exceptionCauseFqcn header cannot be null" );
876
935
Assert .notNull (this .keyExceptionMessage , "keyExceptionMessage header cannot be null" );
877
936
Assert .notNull (this .exceptionMessage , "exceptionMessage header cannot be null" );
878
937
Assert .notNull (this .keyExceptionStacktrace , "keyExceptionStacktrace header cannot be null" );
879
938
Assert .notNull (this .exceptionStacktrace , "exceptionStacktrace header cannot be null" );
880
939
return new DeadLetterPublishingRecoverer .HeaderNames (Builder .this .original .build (),
881
940
new HeaderNames .ExceptionInfo (this .keyExceptionFqcn ,
882
941
this .exceptionFqcn ,
942
+ this .exceptionCauseFqcn ,
883
943
this .keyExceptionMessage ,
884
944
this .exceptionMessage ,
885
945
this .keyExceptionStacktrace ,
0 commit comments