You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2023/02/13 13:02:08 UTC

[camel] 01/06: CAMEL-19040: Backlog tracer to capture exchange properties.

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

commit 5329417c50ed4f971bfce6983b9d125068659043
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon Feb 13 08:46:43 2023 +0100

    CAMEL-19040: Backlog tracer to capture exchange properties.
---
 .../java/org/apache/camel/spi/BacklogTracer.java   |  10 ++
 .../apache/camel/impl/debugger/BacklogTracer.java  |  11 ++
 .../camel/impl/engine/CamelInternalProcessor.java  |   5 +-
 .../mbean/ManagedBacklogTracerMBean.java           |   6 ++
 .../management/mbean/ManagedBacklogTracer.java     |  10 ++
 .../org/apache/camel/support/MessageHelper.java    | 120 ++++++++++++++++-----
 6 files changed, 134 insertions(+), 28 deletions(-)

diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/BacklogTracer.java b/core/camel-api/src/main/java/org/apache/camel/spi/BacklogTracer.java
index 044ac2d9066..580955018b0 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/BacklogTracer.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/BacklogTracer.java
@@ -99,6 +99,16 @@ public interface BacklogTracer {
      */
     void setBodyIncludeFiles(boolean bodyIncludeFiles);
 
+    /**
+     * Trace messages to include exchange properties
+     */
+    boolean isIncludeExchangeProperties();
+
+    /**
+     * Trace messages to include exchange properties
+     */
+    void setIncludeExchangeProperties(boolean includeExchangeProperties);
+
     /**
      * Filter for tracing by route or node id
      */
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/debugger/BacklogTracer.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/debugger/BacklogTracer.java
index 6d509e36e4a..a89131c84c9 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/debugger/BacklogTracer.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/debugger/BacklogTracer.java
@@ -60,6 +60,7 @@ public final class BacklogTracer extends ServiceSupport implements org.apache.ca
     private int bodyMaxChars = 128 * 1024;
     private boolean bodyIncludeStreams;
     private boolean bodyIncludeFiles = true;
+    private boolean includeExchangeProperties = true;
     // a pattern to filter tracing nodes
     private String tracePattern;
     private String[] patterns;
@@ -222,6 +223,16 @@ public final class BacklogTracer extends ServiceSupport implements org.apache.ca
         this.bodyIncludeFiles = bodyIncludeFiles;
     }
 
+    @Override
+    public boolean isIncludeExchangeProperties() {
+        return includeExchangeProperties;
+    }
+
+    @Override
+    public void setIncludeExchangeProperties(boolean includeExchangeProperties) {
+        this.includeExchangeProperties = includeExchangeProperties;
+    }
+
     @Override
     public String getTracePattern() {
         return tracePattern;
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/CamelInternalProcessor.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/CamelInternalProcessor.java
index 0ab81f951f0..d95c803f1d1 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/CamelInternalProcessor.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/CamelInternalProcessor.java
@@ -584,10 +584,11 @@ public class CamelInternalProcessor extends DelegateAsyncProcessor implements In
                 long timestamp = System.currentTimeMillis();
                 String toNode = processorDefinition.getId();
                 String exchangeId = exchange.getExchangeId();
-                String messageAsXml = MessageHelper.dumpAsXml(exchange.getIn(), true, 4,
+                boolean includeExchangeProperties = backlogTracer.isIncludeExchangeProperties();
+                String messageAsXml = MessageHelper.dumpAsXml(exchange.getIn(), includeExchangeProperties, true, 4,
                         true, backlogTracer.isBodyIncludeStreams(), backlogTracer.isBodyIncludeFiles(),
                         backlogTracer.getBodyMaxChars());
-                String messageAsJSon = MessageHelper.dumpAsJSon(exchange.getIn(), true, 4,
+                String messageAsJSon = MessageHelper.dumpAsJSon(exchange.getIn(), includeExchangeProperties, true, 4,
                         true, backlogTracer.isBodyIncludeStreams(), backlogTracer.isBodyIncludeFiles(),
                         backlogTracer.getBodyMaxChars(), true);
 
diff --git a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedBacklogTracerMBean.java b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedBacklogTracerMBean.java
index 61f7c1b9b96..cad1bdbbe9a 100644
--- a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedBacklogTracerMBean.java
+++ b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedBacklogTracerMBean.java
@@ -90,6 +90,12 @@ public interface ManagedBacklogTracerMBean {
     @ManagedAttribute(description = "Whether to include file based message body in the trace message.")
     void setBodyIncludeFiles(boolean bodyIncludeFiles);
 
+    @ManagedAttribute(description = "Whether to include exchange properties in the trace message.")
+    boolean isIncludeExchangeProperties();
+
+    @ManagedAttribute(description = "Whether to include exchange properties in the trace message.")
+    void setIncludeExchangeProperties(boolean includeExchangeProperties);
+
     @ManagedOperation(description = "Dumps the traced messages for the given node or route")
     List<BacklogTracerEventMessage> dumpTracedMessages(String nodeOrRouteId);
 
diff --git a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedBacklogTracer.java b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedBacklogTracer.java
index 7a4c82cd332..19de3926c2d 100644
--- a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedBacklogTracer.java
+++ b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedBacklogTracer.java
@@ -161,6 +161,16 @@ public class ManagedBacklogTracer implements ManagedBacklogTracerMBean {
         backlogTracer.setBodyIncludeFiles(bodyIncludeFiles);
     }
 
+    @Override
+    public boolean isIncludeExchangeProperties() {
+        return backlogTracer.isIncludeExchangeProperties();
+    }
+
+    @Override
+    public void setIncludeExchangeProperties(boolean includeExchangeProperties) {
+        backlogTracer.setIncludeExchangeProperties(includeExchangeProperties);
+    }
+
     @Override
     public List<BacklogTracerEventMessage> dumpTracedMessages(String nodeOrRouteId) {
         return backlogTracer.dumpTracedMessages(nodeOrRouteId);
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 917692421a2..7f69612a3af 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
@@ -471,25 +471,26 @@ public final class MessageHelper {
      */
     public static String dumpAsXml(
             Message message, boolean includeBody, int indent, boolean allowStreams, boolean allowFiles, int maxChars) {
-        return dumpAsXml(message, includeBody, indent, allowStreams, allowStreams, allowFiles, maxChars);
+        return dumpAsXml(message, false, includeBody, indent, allowStreams, allowStreams, allowFiles, maxChars);
     }
 
     /**
      * Dumps the message as a generic XML structure.
      *
-     * @param  message            the message
-     * @param  includeBody        whether or not to include the message body
-     * @param  indent             number of spaces to indent
-     * @param  allowCachedStreams whether to include message body if they are stream cache based
-     * @param  allowStreams       whether to include message body if they are stream based
-     * @param  allowFiles         whether to include message body if they are file based
-     * @param  maxChars           clip body after maximum chars (to avoid very big messages). Use 0 or negative value to
-     *                            not limit at all.
-     * @return                    the XML
+     * @param  message                   the message
+     * @param  includeBody               whether or not to include the message body
+     * @param  includeExchangeProperties whether or not to include exchange properties
+     * @param  indent                    number of spaces to indent
+     * @param  allowCachedStreams        whether to include message body if they are stream cache based
+     * @param  allowStreams              whether to include message body if they are stream based
+     * @param  allowFiles                whether to include message body if they are file based
+     * @param  maxChars                  clip body after maximum chars (to avoid very big messages). Use 0 or negative
+     *                                   value to not limit at all.
+     * @return                           the XML
      */
     public static String dumpAsXml(
-            Message message, boolean includeBody, int indent, boolean allowCachedStreams, boolean allowStreams,
-            boolean allowFiles, int maxChars) {
+            Message message, boolean includeExchangeProperties, boolean includeBody, int indent,
+            boolean allowCachedStreams, boolean allowStreams, boolean allowFiles, int maxChars) {
         StringBuilder sb = new StringBuilder();
 
         StringBuilder prefix = new StringBuilder();
@@ -501,6 +502,42 @@ public final class MessageHelper {
         sb.append(prefix);
         sb.append("<message exchangeId=\"").append(message.getExchange().getExchangeId()).append("\">\n");
 
+        // exchange properties
+        if (includeExchangeProperties && message.getExchange().hasProperties()) {
+            sb.append(prefix);
+            sb.append("  <exchangeProperties>\n");
+            // sort the exchange properties so they are listed A..Z
+            Map<String, Object> properties = new TreeMap<>(message.getExchange().getProperties());
+            for (Map.Entry<String, Object> entry : properties.entrySet()) {
+                Object value = entry.getValue();
+                String type = ObjectHelper.classCanonicalName(value);
+                sb.append(prefix);
+                sb.append("    <exchangeProperty key=\"").append(entry.getKey()).append("\"");
+                if (type != null) {
+                    sb.append(" type=\"").append(type).append("\"");
+                }
+                sb.append(">");
+
+                // dump header value as XML, use Camel type converter to convert
+                // to String
+                if (value != null) {
+                    try {
+                        String xml = message.getExchange().getContext().getTypeConverter().tryConvertTo(String.class,
+                                message.getExchange(), value);
+                        if (xml != null) {
+                            // must always xml encode
+                            sb.append(StringHelper.xmlEncode(xml));
+                        }
+                    } catch (Throwable e) {
+                        // ignore as the body is for logging purpose
+                    }
+                }
+
+                sb.append("</exchangeProperty>\n");
+            }
+            sb.append(prefix);
+            sb.append("  </exchangeProperties>\n");
+        }
         // headers
         if (message.hasHeaders()) {
             sb.append(prefix);
@@ -537,7 +574,6 @@ public final class MessageHelper {
             sb.append(prefix);
             sb.append("  </headers>\n");
         }
-
         if (includeBody) {
             sb.append(prefix);
             sb.append("  <body");
@@ -803,31 +839,63 @@ public final class MessageHelper {
     public static String dumpAsJSon(
             Message message, boolean includeBody, int indent, boolean allowStreams, boolean allowFiles, int maxChars,
             boolean pretty) {
-        return dumpAsJSon(message, includeBody, indent, false, allowStreams, allowFiles, maxChars, pretty);
+        return dumpAsJSon(message, false, includeBody, indent, false, allowStreams, allowFiles, maxChars, pretty);
     }
 
     /**
      * Dumps the message as a generic JSon structure.
      *
-     * @param  message            the message
-     * @param  includeBody        whether or not to include the message body
-     * @param  indent             number of spaces to indent
-     * @param  allowCachedStreams whether to include message body if they are stream cached based
-     * @param  allowStreams       whether to include message body if they are stream based
-     * @param  allowFiles         whether to include message body if they are file based
-     * @param  maxChars           clip body after maximum chars (to avoid very big messages). Use 0 or negative value to
-     *                            not limit at all.
-     * @return                    the JSon
+     * @param  message                   the message
+     * @param  includeExchangeProperties whether or not to include exchange properties
+     * @param  includeBody               whether or not to include the message body
+     * @param  indent                    number of spaces to indent
+     * @param  allowCachedStreams        whether to include message body if they are stream cached based
+     * @param  allowStreams              whether to include message body if they are stream based
+     * @param  allowFiles                whether to include message body if they are file based
+     * @param  maxChars                  clip body after maximum chars (to avoid very big messages). Use 0 or negative
+     *                                   value to not limit at all.
+     * @return                           the JSon
      */
     public static String dumpAsJSon(
-            Message message, boolean includeBody, int indent, boolean allowCachedStreams, boolean allowStreams,
-            boolean allowFiles, int maxChars, boolean pretty) {
+            Message message, boolean includeExchangeProperties, boolean includeBody, int indent,
+            boolean allowCachedStreams, boolean allowStreams, boolean allowFiles, int maxChars, boolean pretty) {
 
         JsonObject root = new JsonObject();
         JsonObject jo = new JsonObject();
         root.put("message", jo);
         jo.put("exchangeId", message.getExchange().getExchangeId());
 
+        // exchange properties
+        if (includeExchangeProperties && message.getExchange().hasProperties()) {
+            JsonArray arr = new JsonArray();
+            // sort the exchange properties so they are listed A..Z
+            Map<String, Object> properties = new TreeMap<>(message.getExchange().getProperties());
+            for (Map.Entry<String, Object> entry : properties.entrySet()) {
+                Object value = entry.getValue();
+                String type = ObjectHelper.classCanonicalName(value);
+                JsonObject jh = new JsonObject();
+                jh.put("key", entry.getKey());
+                if (type != null) {
+                    jh.put("type", type);
+                }
+                // dump property value as JSon, use Camel type converter to convert to String
+                if (value != null) {
+                    try {
+                        String data = message.getExchange().getContext().getTypeConverter().tryConvertTo(String.class,
+                                message.getExchange(), value);
+                        if (data != null) {
+                            jh.put("value", Jsoner.unescape(data));
+                        }
+                    } catch (Throwable e) {
+                        // ignore as the body is for logging purpose
+                    }
+                }
+                arr.add(jh);
+            }
+            if (!arr.isEmpty()) {
+                jo.put("exchangeProperties", arr);
+            }
+        }
         // headers
         if (message.hasHeaders()) {
             JsonArray arr = new JsonArray();
@@ -853,12 +921,12 @@ public final class MessageHelper {
                         // ignore as the body is for logging purpose
                     }
                 }
+                arr.add(jh);
             }
             if (!arr.isEmpty()) {
                 jo.put("headers", arr);
             }
         }
-
         if (includeBody) {
             JsonObject jb = new JsonObject();
             jo.put("body", jb);