This is an automated email from the ASF dual-hosted git repository.

lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git


The following commit(s) were added to refs/heads/rocketmq-studio by this push:
     new 89e6f2615 fix(trace): preserve send status in legacy producer traces 
(#6620)
89e6f2615 is described below

commit 89e6f2615285212d7040f3f11be2c1c54c58adcb
Author: Xiao Yang <[email protected]>
AuthorDate: Thu Oct 15 18:37:19 2026 +0800

    fix(trace): preserve send status in legacy producer traces (#6620)
---
 .../provider/apache/RocketMQMessageProvider.java   |  9 +++-
 .../apache/RocketMQMessageProviderTest.java        | 57 ++++++++++++++++++++++
 2 files changed, 65 insertions(+), 1 deletion(-)

diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQMessageProvider.java
 
b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQMessageProvider.java
index b14f5386c..4afed6fb9 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQMessageProvider.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQMessageProvider.java
@@ -878,11 +878,18 @@ public class RocketMQMessageProvider implements 
MessageProvider {
     // Pub layout (RocketMQ 5.5.0 TraceDataEncoder):
     //             type, time, region, group, topic, msgId,
     //             tags, keys, storeHost, bodyLength, costTime, msgType, 
offsetMsgId, isSuccess
+    // Legacy 13-field records omit offsetMsgId; newer records may append 
clientHost.
     private TraceNodeVO buildProduceNode(String[] f) {
+        // Match the SDK's split behavior when selecting the layout: trailing 
empty columns do not count.
+        int fieldCount = f.length;
+        while (fieldCount > 0 && f[fieldCount - 1].isEmpty()) {
+            fieldCount--;
+        }
+        int successIndex = fieldCount == 13 ? 12 : 13;
         return TraceNodeVO.builder()
                 .title("produce")
                 .timestamp(parseLong(field(f, 1)))
-                .status(parseBoolean(field(f, 13)) ? "finish" : "failed")
+                .status(parseBoolean(field(f, successIndex)) ? "finish" : 
"failed")
                 .costTime(parseLong(field(f, 10)))
                 .description("producer=" + field(f, 3) + ", storeHost=" + 
field(f, 8))
                 .build();
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/provider/apache/RocketMQMessageProviderTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/provider/apache/RocketMQMessageProviderTest.java
index f244e2e82..ff4f09fb4 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/provider/apache/RocketMQMessageProviderTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/provider/apache/RocketMQMessageProviderTest.java
@@ -66,6 +66,8 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.Timeout;
 import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.junit.jupiter.MockitoExtension;
@@ -917,6 +919,61 @@ class RocketMQMessageProviderTest {
         assertThat(record.isBodyTruncated()).isTrue();
     }
 
+    @ParameterizedTest
+    @CsvSource({"13,true,false", "13,false,false", "14,true,false", 
"14,false,false",
+                "15,true,false", "15,false,false", "13,true,true", 
"13,false,true",
+                "14,true,true", "14,false,true", "15,true,true", 
"15,false,true"})
+    void getMessageTraceShouldMatchSdkProducerTraceLayoutsTest(int fieldCount, 
boolean success,
+                                                               boolean 
emptyOptionalFields) throws Exception {
+        List<String> fields = new ArrayList<>(List.of("Pub", "1000", "cn", 
"prod-group", "TopicA", "msg-123",
+                "tag1", "key1", "broker:10911", "15", "50", "0"));
+        if (fieldCount >= 14) {
+            fields.add(fieldCount == 14 && emptyOptionalFields ? "" : 
"offset-1");
+        }
+        fields.add(Boolean.toString(success));
+        if (fieldCount == 15) {
+            fields.add(emptyOptionalFields ? "" : "producer-host:1000");
+        }
+        String context = traceContext(fields.toArray(String[]::new));
+        if (fieldCount == 13 && emptyOptionalFields) {
+            context += TraceConstants.CONTENT_SPLITOR;
+        }
+        String body = traceBody(context);
+        
assertThat(TraceDataEncoder.decoderFromTraceDataString(body).getFirst().isSuccess()).isEqualTo(success);
+        MessageExt traceMessage = new MessageExt();
+        traceMessage.setBody(body.getBytes(StandardCharsets.UTF_8));
+        when(adminExt.queryMessage(anyString(), anyString(), anyInt(), 
anyLong(), anyLong()))
+                .thenReturn(new QueryResult(0L, List.of(traceMessage)));
+
+        TraceRecordVO record = provider.getMessageTrace("instance-a", 
"msg-123", "orders");
+
+        assertThat(record.getNodes()).hasSize(1);
+        TraceNodeVO produce = record.getNodes().getFirst();
+        assertThat(produce.getTitle()).isEqualTo("produce");
+        assertThat(produce.getStatus()).isEqualTo(success ? "finish" : 
"failed");
+        assertThat(produce.getTimestamp()).isEqualTo(1000L);
+        assertThat(produce.getCostTime()).isEqualTo(50L);
+        assertThat(produce.getDescription()).isEqualTo("producer=prod-group, 
storeHost=broker:10911");
+    }
+
+    @Test
+    void 
getMessageTraceByKeyShouldPreserveLegacyProducerSuccessAndFilterOtherKeysTest() 
throws Exception {
+        String matching = traceContext("Pub", "1000", "cn", "prod-group", 
"TopicA", "msg-123",
+                "tag1", "shared-key", "broker:10911", "15", "50", "0", "true");
+        String unrelated = traceContext("Pub", "2000", "cn", "other-group", 
"TopicA", "msg-other",
+                "tag1", "other-key", "broker:10911", "15", "50", "0", "true");
+        MessageExt traceMessage = new MessageExt();
+        traceMessage.setBody(traceBody(matching, 
unrelated).getBytes(StandardCharsets.UTF_8));
+        when(adminExt.queryMessage(anyString(), anyString(), anyInt(), 
anyLong(), anyLong()))
+                .thenReturn(new QueryResult(0L, List.of(traceMessage)));
+
+        TraceRecordVO record = provider.getMessageTraceByKey("instance-a", 
"shared-key", "orders", null);
+
+        assertThat(record.getNodes()).hasSize(1);
+        
assertThat(record.getNodes().getFirst().getStatus()).isEqualTo("finish");
+        
assertThat(record.getNodes().getFirst().getDescription()).contains("prod-group");
+    }
+
     void getMessageTraceParsesBatchedPubAndSubAfterContexts() throws Exception 
{
         // Field order follows RocketMQ 5.5.0 TraceDataEncoder:
         // Pub = type, time, region, group,

Reply via email to