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

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new 08ee8b6113cd CAMEL-24844: message history carries the body's type and 
size per step, shown in the failure table
08ee8b6113cd is described below

commit 08ee8b6113cd22b5de6b31e00c94c2935a0bbef2
Author: Claus Ibsen <[email protected]>
AuthorDate: Sun Sep 20 15:13:16 2026 +0200

    CAMEL-24844: message history carries the body's type and size per step, 
shown in the failure table
    
    The runtime half of CAMEL-24844, the cheap part. The body's class at each
    step existed only in the backlog tracer's dumps, so it was there for the 
last
    completed exchange in dev mode and nowhere else; the message history proper
    carried node and elapsed time only.
    
    MessageHistory gets two default methods, getBodyType() (the canonical class
    of the body as the node was reached, "null" for a null body, null when not
    captured) and getBodySize() (bytes, -1 when not captured or unknown), both
    @since 4.23. The message history factories (default, metrics, micrometer,
    opentelemetry-metrics) fill them when history is on: the type is one
    getClass(), the size comes from the MessageSizeStrategy only when it is
    enabled, which the dev profile does. No message copy.
    
    The Message History table printed with a failure gains a Body type and a 
Size
    column, so a person or a model reading a failure sees where the body turned
    from text into a Map or bytes, on every message, without the tracer. A 
custom
    header/output format with the old four placeholders keeps working.
    
    The backlog debugger's messageHistoryOnBreakpointAsXml gets bodyType and
    bodySize attributes per entry; the debug dev console's history rows carry
    them; the error registry's step strings read
    "route[node] (12 ms) bodyType=java.util.LinkedHashMap bodySize=214".
    
    Closes #26626
    
    Co-Authored-By: Claude Fable 5.1 <[email protected]>
    Claude-Session: https://claude.ai/code/session_01Bp3538HRBPMQkb5ta9xRaj
---
 .../MetricsMessageHistoryFactory.java              |   4 +-
 .../MicrometerMessageHistoryFactory.java           |   5 +-
 .../OpenTelemetryMessageHistoryFactory.java        |   5 +-
 .../main/java/org/apache/camel/MessageHistory.java |  21 ++++
 .../camel/impl/engine/DefaultErrorRegistry.java    |  13 ++-
 .../impl/engine/DefaultMessageHistoryFactory.java  |   1 +
 .../apache/camel/impl/console/DebugDevConsole.java |   6 ++
 .../org/apache/camel/impl/ErrorRegistryTest.java   |  23 ++++
 .../MessageHistoryBodyTypeAndSizeTest.java         | 116 +++++++++++++++++++++
 .../management/mbean/ManagedBacklogDebugger.java   |   3 +
 .../camel/support/DefaultMessageHistory.java       |  44 ++++++++
 .../org/apache/camel/support/MessageHelper.java    |  28 +++--
 12 files changed, 255 insertions(+), 14 deletions(-)

diff --git 
a/components/camel-metrics/src/main/java/org/apache/camel/component/metrics/messagehistory/MetricsMessageHistoryFactory.java
 
b/components/camel-metrics/src/main/java/org/apache/camel/component/metrics/messagehistory/MetricsMessageHistoryFactory.java
index 7828dd7f7fdd..696093ce0f1f 100644
--- 
a/components/camel-metrics/src/main/java/org/apache/camel/component/metrics/messagehistory/MetricsMessageHistoryFactory.java
+++ 
b/components/camel-metrics/src/main/java/org/apache/camel/component/metrics/messagehistory/MetricsMessageHistoryFactory.java
@@ -169,7 +169,9 @@ public class MetricsMessageHistoryFactory extends 
ServiceSupport
         }
 
         Timer timer = metricsRegistry.timer(createName("history", routeId, 
node.getId()));
-        return new MetricsMessageHistory(routeId, node, timer, msg);
+        MetricsMessageHistory answer = new MetricsMessageHistory(routeId, 
node, timer, msg);
+        answer.captureBody(exchange);
+        return answer;
     }
 
     private String createName(String type, String routeId, String id) {
diff --git 
a/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/messagehistory/MicrometerMessageHistoryFactory.java
 
b/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/messagehistory/MicrometerMessageHistoryFactory.java
index e2f00326fec3..eae46a1a8863 100644
--- 
a/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/messagehistory/MicrometerMessageHistoryFactory.java
+++ 
b/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/messagehistory/MicrometerMessageHistoryFactory.java
@@ -161,7 +161,10 @@ public class MicrometerMessageHistoryFactory extends 
ServiceSupport
 
         Route route = camelContext.getRoute(routeId);
         if (route != null) {
-            return new MicrometerMessageHistory(getMeterRegistry(), route, 
namedNode, getNamingStrategy(), msg);
+            MicrometerMessageHistory answer
+                    = new MicrometerMessageHistory(getMeterRegistry(), route, 
namedNode, getNamingStrategy(), msg);
+            answer.captureBody(exchange);
+            return answer;
         } else {
             return null;
         }
diff --git 
a/components/camel-opentelemetry-metrics/src/main/java/org/apache/camel/opentelemetry/metrics/messagehistory/OpenTelemetryMessageHistoryFactory.java
 
b/components/camel-opentelemetry-metrics/src/main/java/org/apache/camel/opentelemetry/metrics/messagehistory/OpenTelemetryMessageHistoryFactory.java
index 32d69fc9082e..5a88e7c0f68e 100644
--- 
a/components/camel-opentelemetry-metrics/src/main/java/org/apache/camel/opentelemetry/metrics/messagehistory/OpenTelemetryMessageHistoryFactory.java
+++ 
b/components/camel-opentelemetry-metrics/src/main/java/org/apache/camel/opentelemetry/metrics/messagehistory/OpenTelemetryMessageHistoryFactory.java
@@ -133,7 +133,10 @@ public class OpenTelemetryMessageHistoryFactory extends 
ServiceSupport
 
         Route route = camelContext.getRoute(routeId);
         if (route != null) {
-            return new OpenTelemetryMessageHistory(timer, getTimeUnit(), 
route, namedNode, getNamingStrategy(), msg);
+            OpenTelemetryMessageHistory answer
+                    = new OpenTelemetryMessageHistory(timer, getTimeUnit(), 
route, namedNode, getNamingStrategy(), msg);
+            answer.captureBody(exchange);
+            return answer;
         } else {
             return null;
         }
diff --git a/core/camel-api/src/main/java/org/apache/camel/MessageHistory.java 
b/core/camel-api/src/main/java/org/apache/camel/MessageHistory.java
index a5906fcfd36a..68d79f0e5b8c 100644
--- a/core/camel-api/src/main/java/org/apache/camel/MessageHistory.java
+++ b/core/camel-api/src/main/java/org/apache/camel/MessageHistory.java
@@ -76,6 +76,27 @@ public interface MessageHistory {
     @Nullable
     Message getMessage();
 
+    /**
+     * The class of the message body when this node was reached (the type the 
body arrived with, before the node
+     * processed it): the canonical class name, the string {@code "null"} when 
the body was null, or null when not
+     * captured. Cheap to capture: the class, no conversion, no copy.
+     *
+     * @since 4.23
+     */
+    default @Nullable String getBodyType() {
+        return null;
+    }
+
+    /**
+     * The size in bytes of the message body when this node was reached, 
computed by the
+     * {@link org.apache.camel.spi.MessageSizeStrategy} when it is enabled: -1 
when not captured or unknown.
+     *
+     * @since 4.23
+     */
+    default long getBodySize() {
+        return -1;
+    }
+
     /**
      * Used specially during debugging where some EIP nodes are not accepted 
for debugging and are essentially skipped.
      * This allows tooling to avoid dumping message history for nodes that did 
not take part in the debugger.
diff --git 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultErrorRegistry.java
 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultErrorRegistry.java
index 72ab35cefe6c..ec3e9810524a 100644
--- 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultErrorRegistry.java
+++ 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultErrorRegistry.java
@@ -216,11 +216,18 @@ public class DefaultErrorRegistry extends 
EventNotifierSupport implements ErrorR
             MessageHistory mh = history.get(i);
             String nodeId = mh.getNode() != null ? mh.getNode().getId() : null;
             long elapsed = mh.getElapsed();
+            String step = mh.getRouteId() + "[" + nodeId + "]";
             if (elapsed > 0) {
-                result[i] = mh.getRouteId() + "[" + nodeId + "] (" + elapsed + 
" ms)";
-            } else {
-                result[i] = mh.getRouteId() + "[" + nodeId + "]";
+                step += " (" + elapsed + " ms)";
+            }
+            // the body as the node was reached: the type it arrived with, and 
its size when known (CAMEL-24844)
+            if (mh.getBodyType() != null) {
+                step += " bodyType=" + mh.getBodyType();
+                if (mh.getBodySize() >= 0) {
+                    step += " bodySize=" + mh.getBodySize();
+                }
             }
+            result[i] = step;
         }
         return result;
     }
diff --git 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultMessageHistoryFactory.java
 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultMessageHistoryFactory.java
index 7f8c361b7e84..2f74035750c2 100644
--- 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultMessageHistoryFactory.java
+++ 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultMessageHistoryFactory.java
@@ -65,6 +65,7 @@ public class DefaultMessageHistoryFactory extends 
ServiceSupport implements Mess
 
         DefaultMessageHistory answer = new DefaultMessageHistory(routeId, 
node, msg);
         answer.setAcceptDebugger(node.acceptDebugger(exchange));
+        answer.captureBody(exchange);
         return answer;
     }
 
diff --git 
a/core/camel-console/src/main/java/org/apache/camel/impl/console/DebugDevConsole.java
 
b/core/camel-console/src/main/java/org/apache/camel/impl/console/DebugDevConsole.java
index d261aa0c2b6f..187d252ba6ec 100644
--- 
a/core/camel-console/src/main/java/org/apache/camel/impl/console/DebugDevConsole.java
+++ 
b/core/camel-console/src/main/java/org/apache/camel/impl/console/DebugDevConsole.java
@@ -350,6 +350,12 @@ public class DebugDevConsole extends AbstractDevConsole {
                 jo.put("routeId", h.getRouteId());
             }
             jo.put("elapsed", h.getElapsed());
+            if (h.getBodyType() != null) {
+                jo.put("bodyType", h.getBodyType());
+            }
+            if (h.getBodySize() >= 0) {
+                jo.put("bodySize", h.getBodySize());
+            }
             jo.put("acceptDebugger", h.isAcceptDebugger());
             jo.put("skipOver", h.isDebugSkipOver());
             if (h.getNode() != null) {
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/impl/ErrorRegistryTest.java 
b/core/camel-core/src/test/java/org/apache/camel/impl/ErrorRegistryTest.java
index c83ffe2c1741..4f17d5ee0cd8 100644
--- a/core/camel-core/src/test/java/org/apache/camel/impl/ErrorRegistryTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/impl/ErrorRegistryTest.java
@@ -222,6 +222,8 @@ public class ErrorRegistryTest extends ContextTestSupport {
         assertNotNull(entry.getMessageHistory(), "Message history should be 
captured when enabled");
         assertTrue(entry.getMessageHistory().length > 0, "Message history 
should have at least one entry");
         assertTrue(entry.getMessageHistory()[0].contains("foo"), "Message 
history should contain route id");
+        // the body as each step was reached (CAMEL-24844)
+        assertTrue(entry.getMessageHistory()[0].contains(" 
bodyType=java.lang.String"), entry.getMessageHistory()[0]);
     }
 
     @Test
@@ -301,6 +303,23 @@ public class ErrorRegistryTest extends ContextTestSupport {
         assertTrue((long) json.get("elapsed") >= 0);
     }
 
+    @Test
+    public void testMessageHistoryStepSaysTheBodyWasNull() throws Exception {
+        getMockEndpoint("mock:dead").expectedMessageCount(1);
+        context.getMessageSizeStrategy().setEnabled(true);
+
+        template.sendBody("direct:nullbody", "Hello World");
+        assertMockEndpointsSatisfied();
+
+        BacklogErrorEventMessage entry = 
context.getErrorRegistry().browse().iterator().next();
+        String[] steps = entry.getMessageHistory();
+        assertNotNull(steps);
+        // the throwException step was reached with a null body (set by the 
step before)
+        String last = steps[steps.length - 1];
+        assertTrue(last.contains("bodyType=null"), last);
+        assertTrue(!last.contains("bodySize="), "no body, no size: " + last);
+    }
+
     @Override
     protected RouteBuilder createRouteBuilder() {
         return new RouteBuilder() {
@@ -314,6 +333,10 @@ public class ErrorRegistryTest extends ContextTestSupport {
                 from("direct:start2").routeId("bar")
                         .throwException(new IllegalArgumentException("Forced 
error 2"));
 
+                from("direct:nullbody").routeId("nullbody")
+                        .setBody().constant(null)
+                        .throwException(new IllegalArgumentException("Forced 
error on a null body"));
+
                 from("direct:unhandled").routeId("unhandled")
                         .errorHandler(noErrorHandler())
                         .throwException(new 
IllegalArgumentException("Unhandled error"));
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/processor/MessageHistoryBodyTypeAndSizeTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/processor/MessageHistoryBodyTypeAndSizeTest.java
new file mode 100644
index 000000000000..7b1c516d5851
--- /dev/null
+++ 
b/core/camel-core/src/test/java/org/apache/camel/processor/MessageHistoryBodyTypeAndSizeTest.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.processor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.Exchange;
+import org.apache.camel.MessageHistory;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.support.MessageHelper;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * The message history carries the body's type and size as each node was 
reached (CAMEL-24844): what a person or a model
+ * needs to see where the body changed from text into a Map or bytes, on every 
message and without the tracer.
+ */
+public class MessageHistoryBodyTypeAndSizeTest extends ContextTestSupport {
+
+    @Test
+    public void testBodyTypeAndSizePerStep() throws Exception {
+        context.getMessageSizeStrategy().setEnabled(true);
+        getMockEndpoint("mock:result").expectedMessageCount(1);
+
+        Exchange out = template.request("direct:start", e -> 
e.getMessage().setBody("Hello World"));
+        assertMockEndpointsSatisfied();
+
+        List<MessageHistory> history = 
out.getProperty(Exchange.MESSAGE_HISTORY, List.class);
+        assertNotNull(history);
+        assertEquals(4, history.size());
+
+        // as each step was reached: the text sent, the bytes the first step 
made, the list the second step made
+        assertEquals("a", history.get(0).getNode().getId());
+        assertEquals("java.lang.String", history.get(0).getBodyType());
+        assertEquals(11, history.get(0).getBodySize());
+
+        assertEquals("b", history.get(1).getNode().getId());
+        assertEquals("byte[]", history.get(1).getBodyType());
+        assertEquals(11, history.get(1).getBodySize());
+
+        assertEquals("c", history.get(2).getNode().getId());
+        assertEquals("java.util.ArrayList", history.get(2).getBodyType());
+        assertEquals(3, history.get(2).getBodySize(), "the size strategy 
counts the elements of a collection");
+
+        // a null body is shown as such, not left blank like a body that was 
not captured
+        assertEquals("d", history.get(3).getNode().getId());
+        assertEquals("null", history.get(3).getBodyType());
+        assertEquals(-1, history.get(3).getBodySize(), "no body, no size");
+
+        // the failure table shows both columns
+        String table = MessageHelper.dumpMessageHistoryStacktrace(out, null, 
false);
+        assertTrue(table.contains("Body type"), table);
+        assertTrue(table.contains("java.lang.String"), table);
+        assertTrue(table.contains("byte[]"), table);
+        assertTrue(table.contains("java.util.ArrayList"), table);
+        assertTrue(table.contains("null"), table);
+        // the route's own row (the body as it is now, null after step c) 
shows no size either
+        // (the row is found by its from[] label as the route id is auto 
assigned and depends on the JVM's test order)
+        String routeRow = table.lines().filter(l -> 
l.contains("from[direct://start]")).findFirst().orElse("");
+        assertTrue(routeRow.contains("null") && 
!routeRow.trim().endsWith("0"), "route row: " + routeRow);
+    }
+
+    @Test
+    public void testTypeCapturedSizeNotWhenTheStrategyIsOff() throws Exception 
{
+        // the default outside the dev profile: the type is always captured 
(one class lookup), the size is not
+        context.getMessageSizeStrategy().setEnabled(false);
+        getMockEndpoint("mock:result").expectedMessageCount(1);
+
+        Exchange out = template.request("direct:start", e -> 
e.getMessage().setBody("Hello World"));
+        assertMockEndpointsSatisfied();
+
+        List<MessageHistory> history = 
out.getProperty(Exchange.MESSAGE_HISTORY, List.class);
+        assertEquals(4, history.size());
+        assertEquals("java.lang.String", history.get(0).getBodyType());
+        assertEquals("byte[]", history.get(1).getBodyType());
+        assertEquals("null", history.get(3).getBodyType());
+        for (MessageHistory h : history) {
+            assertEquals(-1, h.getBodySize(), h.getNode().getId());
+        }
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                context.setMessageHistory(true);
+                context.getMessageHistoryFactory().setNodePattern("step");
+                from("direct:start")
+                        .step("a").convertBodyTo(byte[].class).end()
+                        .step("b").transform().constant(new 
ArrayList<>(List.of(1, 2, 3))).end()
+                        .step("c").process(e -> 
e.getMessage().setBody(null)).end()
+                        .step("d").to("mock:result").end();
+            }
+        };
+    }
+}
diff --git 
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedBacklogDebugger.java
 
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedBacklogDebugger.java
index b52f79859a6d..4a85f6badc23 100644
--- 
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedBacklogDebugger.java
+++ 
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedBacklogDebugger.java
@@ -478,6 +478,9 @@ public class ManagedBacklogDebugger implements 
ManagedBacklogDebuggerMBean {
                             .append(" 
processorId=\"").append(StringHelper.xmlEncode(id)).append("\"")
                             .append(" 
processor=\"").append(StringHelper.xmlEncode(label)).append("\"")
                             .append(" elapsed=\"").append(elapsed).append("\"")
+                            .append(history.getBodyType() != null
+                                    ? " bodyType=\"" + 
StringHelper.xmlEncode(history.getBodyType()) + "\"" : "")
+                            .append(history.getBodySize() >= 0 ? " 
bodySize=\"" + history.getBodySize() + "\"" : "")
                             .append("/>\n");
                 }
             }
diff --git 
a/core/camel-support/src/main/java/org/apache/camel/support/DefaultMessageHistory.java
 
b/core/camel-support/src/main/java/org/apache/camel/support/DefaultMessageHistory.java
index a2de8ce6c12c..abffe9c4ced0 100644
--- 
a/core/camel-support/src/main/java/org/apache/camel/support/DefaultMessageHistory.java
+++ 
b/core/camel-support/src/main/java/org/apache/camel/support/DefaultMessageHistory.java
@@ -16,9 +16,13 @@
  */
 package org.apache.camel.support;
 
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
 import org.apache.camel.Message;
 import org.apache.camel.MessageHistory;
 import org.apache.camel.NamedNode;
+import org.apache.camel.spi.MessageSizeStrategy;
+import org.apache.camel.util.ObjectHelper;
 
 /**
  * Default {@link org.apache.camel.MessageHistory}.
@@ -33,6 +37,8 @@ public class DefaultMessageHistory implements MessageHistory {
     private boolean acceptDebugger;
     private boolean debugSkipOver;
     private long elapsed;
+    private String bodyType;
+    private long bodySize = -1;
 
     public DefaultMessageHistory(String routeId, NamedNode node) {
         this(routeId, node, null);
@@ -50,6 +56,44 @@ public class DefaultMessageHistory implements MessageHistory 
{
         return routeId;
     }
 
+    @Override
+    public String getBodyType() {
+        return bodyType;
+    }
+
+    public void setBodyType(String bodyType) {
+        this.bodyType = bodyType;
+    }
+
+    @Override
+    public long getBodySize() {
+        return bodySize;
+    }
+
+    public void setBodySize(long bodySize) {
+        this.bodySize = bodySize;
+    }
+
+    /**
+     * Captures the body's type and size as the node is reached: the type is 
one class lookup ({@code "null"} for a null
+     * body), the size the {@link MessageSizeStrategy}'s (lengths only, no 
reading or conversion) and only when that
+     * strategy is enabled. For every factory that builds a history entry 
(CAMEL-24844).
+     */
+    public void captureBody(Exchange exchange) {
+        Message current = exchange.getMessage();
+        Object body = current.getBody();
+        bodyType = body != null ? ObjectHelper.classCanonicalName(body) : 
"null";
+        if (body == null) {
+            // no body, no size: "null" says it, and 0 would read as an empty 
text or byte array
+            return;
+        }
+        CamelContext context = exchange.getContext();
+        MessageSizeStrategy sizeStrategy = context != null ? 
context.getMessageSizeStrategy() : null;
+        if (sizeStrategy != null && sizeStrategy.isEnabled()) {
+            bodySize = sizeStrategy.computeBodySize(current);
+        }
+    }
+
     @Override
     public NamedNode getNode() {
         return node;
diff --git 
a/core/camel-support/src/main/java/org/apache/camel/support/MessageHelper.java 
b/core/camel-support/src/main/java/org/apache/camel/support/MessageHelper.java
index 2cc133b2abe4..3371aa18fb2a 100644
--- 
a/core/camel-support/src/main/java/org/apache/camel/support/MessageHelper.java
+++ 
b/core/camel-support/src/main/java/org/apache/camel/support/MessageHelper.java
@@ -53,8 +53,8 @@ import org.apache.camel.util.json.Jsoner;
  */
 public final class MessageHelper {
 
-    private static final String MESSAGE_HISTORY_HEADER = "%-40s %-30s %-50s 
%-12s";
-    private static final String MESSAGE_HISTORY_OUTPUT = "%-40.40s %-30.30s 
%-50.50s %12.12s";
+    private static final String MESSAGE_HISTORY_HEADER = "%-40s %-30s %-50s 
%-12s %-32s %-9s";
+    private static final String MESSAGE_HISTORY_OUTPUT = "%-40.40s %-30.30s 
%-50.50s %12.12s %-32.32s %9.9s";
 
     /**
      * Utility classes should not have a public constructor.
@@ -768,15 +768,24 @@ public final class MessageHelper {
         }
         sb.append("\n");
         sb.append(
-                
"---------------------------------------------------------------------------------------------------------------------------------------\n");
+                
"----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n");
         String goMessageHistoryHeader = 
exchange.getContext().getGlobalOption(Exchange.MESSAGE_HISTORY_HEADER_FORMAT);
         sb.append(String.format(goMessageHistoryHeader == null ? 
MESSAGE_HISTORY_HEADER : goMessageHistoryHeader,
-                "Source", "ID", "Processor", "Elapsed (ms)"));
+                "Source", "ID", "Processor", "Elapsed (ms)", "Body type", 
"Size"));
         sb.append("\n");
 
+        // the body as it is now, for the route's own row (the history rows 
carry the body as each node was reached)
+        Object body = exchange.getMessage().getBody();
+        String bodyType = body != null ? ObjectHelper.classCanonicalName(body) 
: "null";
+        String bodySize = "";
+        if (body != null && exchange.getContext().getMessageSizeStrategy() != 
null
+                && exchange.getContext().getMessageSizeStrategy().isEnabled()) 
{
+            long size = 
exchange.getContext().getMessageSizeStrategy().computeBodySize(exchange.getMessage());
+            bodySize = size >= 0 ? Long.toString(size) : "";
+        }
         String goMessageHistoryOutput = 
exchange.getContext().getGlobalOption(Exchange.MESSAGE_HISTORY_OUTPUT_FORMAT);
         goMessageHistoryOutput = goMessageHistoryOutput == null ? 
MESSAGE_HISTORY_OUTPUT : goMessageHistoryOutput;
-        sb.append(String.format(goMessageHistoryOutput, loc, routeId + "/" + 
id, label, elapsed));
+        sb.append(String.format(goMessageHistoryOutput, loc, routeId + "/" + 
id, label, elapsed, bodyType, bodySize));
         sb.append("\n");
 
         if (list == null || list.isEmpty()) {
@@ -803,7 +812,7 @@ public final class MessageHelper {
                 label = URISupport.sanitizeUri(StringHelper.limitLength(label, 
100));
                 // we do not have elapsed time
                 sb.append("\t...\n");
-                sb.append(String.format(goMessageHistoryOutput, loc, routeId + 
"/" + id, label, 0));
+                sb.append(String.format(goMessageHistoryOutput, loc, routeId + 
"/" + id, label, 0, "", ""));
                 sb.append("\n");
             }
         } else {
@@ -824,7 +833,10 @@ public final class MessageHelper {
                 // fast
                 label = 
URISupport.sanitizeUri(StringHelper.limitLength(history.getNode().getLabel(), 
100));
 
-                sb.append(String.format(goMessageHistoryOutput, loc, routeId + 
"/" + id, label, history.getElapsed()));
+                String type = history.getBodyType() != null ? 
history.getBodyType() : "";
+                String size = history.getBodySize() >= 0 ? 
Long.toString(history.getBodySize()) : "";
+                sb.append(String.format(goMessageHistoryOutput, loc, routeId + 
"/" + id, label, history.getElapsed(),
+                        type, size));
                 sb.append("\n");
             }
         }
@@ -832,7 +844,7 @@ public final class MessageHelper {
         if (exchangeFormatter != null) {
             sb.append("\nExchange\n");
             sb.append(
-                    
"---------------------------------------------------------------------------------------------------------------------------------------\n");
+                    
"----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n");
             sb.append(exchangeFormatter.format(exchange));
             sb.append("\n");
         }

Reply via email to