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);