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 17:33:10 UTC

[camel] branch main updated (99d6a39dc0a -> 4672fe8298f)

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

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


    from 99d6a39dc0a Sync deps
     new 39f3d61f912 CAMEL-19033: camel-jbang - Add trace command
     new 34a1bf1ffc0 CAMEL-19033: camel-jbang - get trace in color output of json so its easier to read
     new 4672fe8298f CAMEL-19033: camel-jbang - get trace in color output of json so its easier to read

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../org/apache/camel/support/MessageHelper.java    |  39 +++---
 .../dsl/jbang/core/commands/process/ListTrace.java |  77 +++++++++--
 .../camel/dsl/jbang/core/common/JSonHelper.java    |  59 ++++++++
 .../java/org/apache/camel/util/json/Jsoner.java    | 148 ++++++++++++++++++++-
 .../java/org/apache/camel/util/json/Yytoken.java   |   8 +-
 ...eOrderedTest.java => JSonerColorPrintTest.java} |  59 ++++----
 .../org/apache/camel/util/json/JSonerTest.java     |  25 ++--
 7 files changed, 344 insertions(+), 71 deletions(-)
 create mode 100644 dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/JSonHelper.java
 copy tooling/camel-util-json/src/test/java/org/apache/camel/util/json/{JsonSimpleOrderedTest.java => JSonerColorPrintTest.java} (54%)
 copy core/camel-console/src/test/java/org/apache/camel/impl/console/DefaultDevConsolesLoaderTest.java => tooling/camel-util-json/src/test/java/org/apache/camel/util/json/JSonerTest.java (64%)


[camel] 01/03: CAMEL-19033: camel-jbang - Add trace command

Posted by da...@apache.org.
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 39f3d61f912136ca6e09487962207ee2644ba803
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon Feb 13 14:50:39 2023 +0100

    CAMEL-19033: camel-jbang - Add trace command
---
 .../dsl/jbang/core/commands/process/ListTrace.java | 39 +++++++++++++++++++---
 1 file changed, 34 insertions(+), 5 deletions(-)

diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListTrace.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListTrace.java
index 0fdde579aef..b9aaf09c32a 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListTrace.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListTrace.java
@@ -47,9 +47,13 @@ public class ListTrace extends ProcessWatchCommand {
                         description = "Sort by pid, name or age", defaultValue = "pid")
     String sort;
 
-    @CommandLine.Option(names = { "--last" },
-                        description = "Only output last message")
-    boolean last;
+    @CommandLine.Option(names = { "--latest" },
+                        description = "Only output traces of latest message")
+    boolean latest;
+
+    @CommandLine.Option(names = { "--brief" },
+                        description = "Brief mode to only show traces of input and output (no intermediate processing steps)")
+    boolean brief;
 
     @CommandLine.Option(names = { "--pretty" },
                         description = "Pretty print traced message")
@@ -97,7 +101,7 @@ public class ListTrace extends ProcessWatchCommand {
                     new Column().header("ROUTE").dataAlign(HorizontalAlign.LEFT).maxWidth(25, OverflowBehaviour.ELLIPSIS_RIGHT)
                             .with(r -> r.routeId),
                     new Column().header("ID").dataAlign(HorizontalAlign.LEFT).maxWidth(25, OverflowBehaviour.ELLIPSIS_RIGHT)
-                            .with(r -> r.nodeId),
+                            .with(this::getId),
                     new Column().header("AGE").dataAlign(HorizontalAlign.RIGHT).with(this::getTimestamp),
                     new Column().header("MESSAGE").dataAlign(HorizontalAlign.LEFT).maxWidth(110, OverflowBehaviour.NEWLINE)
                             .with(this::getMessage))));
@@ -118,22 +122,31 @@ public class ListTrace extends ProcessWatchCommand {
                     row = row.copy();
                     JsonObject jo = (JsonObject) o;
                     row.uid = jo.getLong("uid");
+                    row.first = jo.getBoolean("first");
+                    row.last = jo.getBoolean("last");
                     row.routeId = jo.getString("routeId");
                     row.nodeId = jo.getString("nodeId");
                     Long ts = jo.getLong("timestamp");
                     if (ts != null) {
                         row.timestamp = ts;
                     }
+                    row.elapsed = jo.getLong("elapsed");
+                    row.failed = jo.getBoolean("failed");
+                    row.done = jo.getBoolean("done");
                     row.message = jo.getMap("message");
+                    row.exception = jo.getMap("exception");
                     lastId = getExchangeId(row);
                     local.add(row);
                 }
             }
-            if (last && lastId != null) {
+            if (latest && lastId != null) {
                 // filter out all that does not match last exchange id
                 final String target = lastId;
                 local.removeIf(r -> !target.equals(getExchangeId(r)));
             }
+            if (brief) {
+                local.removeIf(r -> !r.first && !r.last);
+            }
             rows.addAll(local);
         }
     }
@@ -164,6 +177,16 @@ public class ListTrace extends ProcessWatchCommand {
         return "" + r.uid;
     }
 
+    private String getId(Row r) {
+        if (r.first) {
+            return "*-->";
+        } else if (r.last) {
+            return "*<--";
+        } else {
+            return "" + r.nodeId;
+        }
+    }
+
     private String getExchangeId(Row r) {
         return r.message.getString("exchangeId");
     }
@@ -198,11 +221,17 @@ public class ListTrace extends ProcessWatchCommand {
     private static class Row implements Cloneable {
         String pid;
         String name;
+        boolean first;
+        boolean last;
         long uid;
         String routeId;
         String nodeId;
         long timestamp;
+        long elapsed;
+        boolean done;
+        boolean failed;
         JsonObject message;
+        JsonObject exception;
 
         Row copy() {
             try {


[camel] 02/03: CAMEL-19033: camel-jbang - get trace in color output of json so its easier to read

Posted by da...@apache.org.
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 34a1bf1ffc08d005ff095a1883da467b4aa2e786
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon Feb 13 16:29:23 2023 +0100

    CAMEL-19033: camel-jbang - get trace in color output of json so its easier to read
---
 .../dsl/jbang/core/commands/process/ListTrace.java |  38 ++++++-
 .../camel/dsl/jbang/core/common/JSonHelper.java    |  54 ++++++++++
 .../java/org/apache/camel/util/json/Jsoner.java    | 111 +++++++++++++++++++++
 .../java/org/apache/camel/util/json/Yytoken.java   |   8 +-
 .../camel/util/json/JSonerColorPrintTest.java      |  83 +++++++++++++++
 5 files changed, 287 insertions(+), 7 deletions(-)

diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListTrace.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListTrace.java
index b9aaf09c32a..a77ea0caf96 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListTrace.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListTrace.java
@@ -27,6 +27,7 @@ import com.github.freva.asciitable.Column;
 import com.github.freva.asciitable.HorizontalAlign;
 import com.github.freva.asciitable.OverflowBehaviour;
 import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.dsl.jbang.core.common.JSonHelper;
 import org.apache.camel.dsl.jbang.core.common.ProcessHelper;
 import org.apache.camel.util.IOHelper;
 import org.apache.camel.util.TimeUtils;
@@ -92,7 +93,7 @@ public class ListTrace extends ProcessWatchCommand {
         rows.sort(this::sortRow);
 
         if (!rows.isEmpty()) {
-            System.out.println(AsciiTable.getTable(AsciiTable.NO_BORDERS, rows, Arrays.asList(
+            String data = AsciiTable.getTable(AsciiTable.NO_BORDERS, rows, Arrays.asList(
                     new Column().header("PID").headerAlign(HorizontalAlign.CENTER).with(r -> r.pid),
                     new Column().header("NAME").dataAlign(HorizontalAlign.LEFT).maxWidth(30, OverflowBehaviour.ELLIPSIS_RIGHT)
                             .with(r -> r.name),
@@ -103,8 +104,23 @@ public class ListTrace extends ProcessWatchCommand {
                     new Column().header("ID").dataAlign(HorizontalAlign.LEFT).maxWidth(25, OverflowBehaviour.ELLIPSIS_RIGHT)
                             .with(this::getId),
                     new Column().header("AGE").dataAlign(HorizontalAlign.RIGHT).with(this::getTimestamp),
-                    new Column().header("MESSAGE").dataAlign(HorizontalAlign.LEFT).maxWidth(110, OverflowBehaviour.NEWLINE)
-                            .with(this::getMessage))));
+                    new Column().header("ELAPSED").dataAlign(HorizontalAlign.RIGHT).with(this::getElapsed),
+                    new Column().header("FAILED").dataAlign(HorizontalAlign.RIGHT).with(this::getFailed)));
+            String[] arr = data.split(System.lineSeparator());
+            // print header
+            System.out.println(arr[0]);
+            // mix column and message (master/detail) mode
+            for (int i = 0; i < rows.size(); i++) {
+                String s = arr[i + 1];
+                System.out.println(s);
+                String json = getMessage(rows.get(i));
+                // pad with 8 spaces to indent json data
+                String[] lines = json.split(System.lineSeparator());
+                for (String line : lines) {
+                    System.out.print("        ");
+                    System.out.println(line);
+                }
+            }
         }
 
         return 0;
@@ -173,6 +189,20 @@ public class ListTrace extends ProcessWatchCommand {
         return "";
     }
 
+    private String getElapsed(Row r) {
+        if (r.elapsed > 0) {
+            return TimeUtils.printDuration(r.elapsed, true);
+        }
+        return "";
+    }
+
+    private String getFailed(Row r) {
+        if (r.failed) {
+            return "1";
+        }
+        return "0";
+    }
+
     private String getUid(Row r) {
         return "" + r.uid;
     }
@@ -194,7 +224,7 @@ public class ListTrace extends ProcessWatchCommand {
     private String getMessage(Row r) {
         String s = r.message.toJson();
         if (pretty) {
-            s = Jsoner.prettyPrint(s, 2);
+            s = JSonHelper.colorPrint(s, 2);
         }
         return s;
     }
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/JSonHelper.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/JSonHelper.java
new file mode 100644
index 00000000000..7d1b06f2d35
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/JSonHelper.java
@@ -0,0 +1,54 @@
+/*
+ * 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.dsl.jbang.core.common;
+
+import org.apache.camel.util.json.Jsoner;
+import org.apache.camel.util.json.Yytoken;
+import org.fusesource.jansi.Ansi;
+
+public final class JSonHelper {
+
+    private JSonHelper() {
+    }
+
+    /**
+     * Prints the JSon in ANSi color (similar to jq)
+     */
+    public static String colorPrint(String json, int spaces) {
+        return Jsoner.colorPrint(json, spaces, new Jsoner.ColorPrintElement() {
+            Yytoken.Types prev;
+
+            @Override
+            public String color(Yytoken.Types type, Object value) {
+                String s = value.toString();
+                switch (type) {
+                    case COLON, COMMA, LEFT_SQUARE, RIGHT_SQUARE, LEFT_BRACE, RIGHT_BRACE ->
+                        s = Ansi.ansi().fg(Ansi.Color.WHITE).bold().a(s).reset().toString();
+                    case VALUE -> {
+                        if (Yytoken.Types.COLON == prev) {
+                            s = Ansi.ansi().fg(Ansi.Color.GREEN).a(s).reset().toString();
+                        } else {
+                            s = Ansi.ansi().fgBright(Ansi.Color.BLUE).a(s).reset().toString();
+                        }
+                    }
+                }
+                prev = type;
+                return s;
+            }
+        });
+    }
+}
diff --git a/tooling/camel-util-json/src/main/java/org/apache/camel/util/json/Jsoner.java b/tooling/camel-util-json/src/main/java/org/apache/camel/util/json/Jsoner.java
index a2624a74478..573fe7eb484 100644
--- a/tooling/camel-util-json/src/main/java/org/apache/camel/util/json/Jsoner.java
+++ b/tooling/camel-util-json/src/main/java/org/apache/camel/util/json/Jsoner.java
@@ -732,6 +732,117 @@ public final class Jsoner {
         return returnable.toString();
     }
 
+    @FunctionalInterface
+    public interface ColorPrintElement {
+        String color(Yytoken.Types type, Object value);
+    }
+
+    public static String colorPrint(final String printable, final ColorPrintElement color) {
+        return Jsoner.colorPrint(printable, "\t", Integer.MAX_VALUE, color);
+    }
+
+    public static String colorPrint(final String printable, final int spaces, final ColorPrintElement color) {
+        if (spaces > 10 || spaces < 2) {
+            throw new IllegalArgumentException("Indentation with spaces must be between 2 and 10.");
+        }
+        final StringBuilder indentation = new StringBuilder("");
+        for (int i = 0; i < spaces; i++) {
+            indentation.append(" ");
+        }
+        return Jsoner.colorPrint(printable, indentation.toString(), Integer.MAX_VALUE, color);
+    }
+
+    public static String colorPrint(
+            final String printable, final String indentation, final int depth, ColorPrintElement color) {
+        final Yylex lexer = new Yylex(new StringReader(printable));
+        Yytoken lexed;
+        final StringBuilder returnable = new StringBuilder();
+        int level = 0;
+        try {
+            do {
+                lexed = Jsoner.lexNextToken(lexer);
+                switch (lexed.getType()) {
+                    case COLON:
+                        returnable.append(color.color(Yytoken.Types.COLON, ":")).append(" ");
+                        break;
+                    case COMMA:
+                        returnable.append(color.color(Yytoken.Types.COMMA, lexed.getValue()));
+                        if (level <= depth) {
+                            returnable.append("\n");
+                            for (int i = 0; i < level; i++) {
+                                returnable.append(indentation);
+                            }
+                        } else {
+                            returnable.append(" ");
+                        }
+                        break;
+                    case END:
+                        returnable.append("\n");
+                        break;
+                    case LEFT_BRACE:
+                        returnable.append(color.color(Yytoken.Types.LEFT_BRACE, lexed.getValue()));
+                        if (++level <= depth) {
+                            returnable.append("\n");
+                            for (int i = 0; i < level; i++) {
+                                returnable.append(indentation);
+                            }
+                        } else {
+                            returnable.append(" ");
+                        }
+                        break;
+                    case LEFT_SQUARE:
+                        returnable.append(color.color(Yytoken.Types.LEFT_SQUARE, lexed.getValue()));
+                        if (++level <= depth) {
+                            returnable.append("\n");
+                            for (int i = 0; i < level; i++) {
+                                returnable.append(indentation);
+                            }
+                        } else {
+                            returnable.append(" ");
+                        }
+                        break;
+                    case RIGHT_BRACE:
+                        if (level-- <= depth) {
+                            returnable.append("\n");
+                            for (int i = 0; i < level; i++) {
+                                returnable.append(indentation);
+                            }
+                        } else {
+                            returnable.append(" ");
+                        }
+                        returnable.append(color.color(Yytoken.Types.RIGHT_BRACE, lexed.getValue()));
+                        break;
+                    case RIGHT_SQUARE:
+                        if (level-- <= depth) {
+                            returnable.append("\n");
+                            for (int i = 0; i < level; i++) {
+                                returnable.append(indentation);
+                            }
+                        } else {
+                            returnable.append(" ");
+                        }
+                        returnable.append(color.color(Yytoken.Types.RIGHT_SQUARE, lexed.getValue()));
+                        break;
+                    default:
+                        if (lexed.getValue() instanceof String) {
+                            String s = "\"" + Jsoner.escape((String) lexed.getValue()) + "\"";
+                            returnable.append(color.color(Yytoken.Types.VALUE, s));
+                        } else {
+                            returnable.append(color.color(Yytoken.Types.VALUE, lexed.getValue()));
+                        }
+                        break;
+                }
+            } while (!lexed.getType().equals(Yytoken.Types.END));
+        } catch (final DeserializationException caught) {
+            /* This is according to the method's contract. */
+            return null;
+        } catch (final IOException caught) {
+            /* See StringReader. */
+            return null;
+        }
+        return returnable.toString();
+    }
+
     /**
      * A convenience method that assumes a StringWriter.
      *
diff --git a/tooling/camel-util-json/src/main/java/org/apache/camel/util/json/Yytoken.java b/tooling/camel-util-json/src/main/java/org/apache/camel/util/json/Yytoken.java
index 5d1a583969f..5ef989f7233 100644
--- a/tooling/camel-util-json/src/main/java/org/apache/camel/util/json/Yytoken.java
+++ b/tooling/camel-util-json/src/main/java/org/apache/camel/util/json/Yytoken.java
@@ -21,9 +21,9 @@ package org.apache.camel.util.json;
  *
  * @since 2.0.0
  */
-class Yytoken {
+public class Yytoken {
     /** Represents the different kinds of tokens. */
-    enum Types {
+    public enum Types {
         /** Tokens of this type will always have a value of ":" */
         COLON,
         /** Tokens of this type will always have a value of "," */
@@ -41,7 +41,9 @@ class Yytoken {
         /** Tokens of this type will always have a value of "}" */
         RIGHT_BRACE,
         /** Tokens of this type will always have a value of "]" */
-        RIGHT_SQUARE;
+        RIGHT_SQUARE,
+        /** Represent the value (not a parsing token but used during color print) */
+        VALUE;
     }
 
     private final Types type;
diff --git a/tooling/camel-util-json/src/test/java/org/apache/camel/util/json/JSonerColorPrintTest.java b/tooling/camel-util-json/src/test/java/org/apache/camel/util/json/JSonerColorPrintTest.java
new file mode 100644
index 00000000000..436835072f1
--- /dev/null
+++ b/tooling/camel-util-json/src/test/java/org/apache/camel/util/json/JSonerColorPrintTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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.util.json;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class JSonerColorPrintTest {
+
+    @Test
+    public void testColor() throws Exception {
+        InputStream is = new FileInputStream("src/test/resources/bean.json");
+        String json = loadText(is);
+
+        String color = Jsoner.colorPrint(json, new Jsoner.ColorPrintElement() {
+            Yytoken.Types prev;
+
+            @Override
+            public String color(Yytoken.Types type, Object value) {
+                String answer;
+                if (Yytoken.Types.VALUE == type) {
+                    if (Yytoken.Types.COLON == prev) {
+                        // value
+                        answer = "GREEN" + value.toString();
+                    } else {
+                        // value
+                        answer = "BLUE" + value.toString();
+                    }
+                } else {
+                    answer = value.toString();
+                }
+                prev = type;
+                return answer;
+            }
+        });
+
+        Assertions.assertTrue(color.contains("BLUE\"title\": GREEN\"Bean\""));
+    }
+
+    public static String loadText(InputStream in) throws IOException {
+        StringBuilder builder = new StringBuilder();
+        InputStreamReader isr = new InputStreamReader(in);
+
+        try {
+            BufferedReader reader = new BufferedReader(isr);
+
+            while (true) {
+                String line = reader.readLine();
+                if (line == null) {
+                    line = builder.toString();
+                    return line;
+                }
+
+                builder.append(line);
+                builder.append("\n");
+            }
+        } finally {
+            isr.close();
+            in.close();
+        }
+    }
+
+}


[camel] 03/03: CAMEL-19033: camel-jbang - get trace in color output of json so its easier to read

Posted by da...@apache.org.
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 4672fe8298fa91a03d0c991a1b061be95403b405
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon Feb 13 18:32:53 2023 +0100

    CAMEL-19033: camel-jbang - get trace in color output of json so its easier to read
---
 .../org/apache/camel/support/MessageHelper.java    | 39 ++++++++++++--------
 .../camel/dsl/jbang/core/common/JSonHelper.java    |  7 +++-
 .../java/org/apache/camel/util/json/Jsoner.java    | 37 ++++++++++++++++++-
 .../org/apache/camel/util/json/JSonerTest.java     | 41 ++++++++++++++++++++++
 4 files changed, 107 insertions(+), 17 deletions(-)

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 ee85d1603b4..d4a7a3db911 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
@@ -881,17 +881,21 @@ public final class MessageHelper {
                 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));
+                    Object s = Jsoner.trySerialize(value);
+                    if (s == null) {
+                        // cannot JSon serialize out of the box, so we need to use string value
+                        try {
+                            s = message.getExchange().getContext().getTypeConverter().tryConvertTo(String.class,
+                                    message.getExchange(), value);
+                        } catch (Throwable e) {
+                            // ignore
                         }
-                    } catch (Throwable e) {
-                        // ignore as the body is for logging purpose
+                    } else {
+                        // use the value as-is because it can be serialized in json
+                        s = value;
                     }
+                    jh.put("value", s);
                 }
                 arr.add(jh);
             }
@@ -914,15 +918,20 @@ public final class MessageHelper {
                 }
                 // dump header 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));
+                    Object s = Jsoner.trySerialize(value);
+                    if (s == null) {
+                        // cannot JSon serialize out of the box, so we need to use string value
+                        try {
+                            s = message.getExchange().getContext().getTypeConverter().tryConvertTo(String.class,
+                                    message.getExchange(), value);
+                        } catch (Throwable e) {
+                            // ignore
                         }
-                    } catch (Throwable e) {
-                        // ignore as the body is for logging purpose
+                    } else {
+                        // use the value as-is because it can be serialized in json
+                        s = value;
                     }
+                    jh.put("value", s);
                 }
                 arr.add(jh);
             }
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/JSonHelper.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/JSonHelper.java
index 7d1b06f2d35..b2c1bb22194 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/JSonHelper.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/JSonHelper.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.dsl.jbang.core.common;
 
+import org.apache.camel.util.StringHelper;
 import org.apache.camel.util.json.Jsoner;
 import org.apache.camel.util.json.Yytoken;
 import org.fusesource.jansi.Ansi;
@@ -40,7 +41,11 @@ public final class JSonHelper {
                         s = Ansi.ansi().fg(Ansi.Color.WHITE).bold().a(s).reset().toString();
                     case VALUE -> {
                         if (Yytoken.Types.COLON == prev) {
-                            s = Ansi.ansi().fg(Ansi.Color.GREEN).a(s).reset().toString();
+                            if (StringHelper.isQuoted(s)) {
+                                s = Ansi.ansi().fg(Ansi.Color.GREEN).a(s).reset().toString();
+                            } else {
+                                s = Ansi.ansi().fg(Ansi.Color.WHITE).a(s).reset().toString();
+                            }
                         } else {
                             s = Ansi.ansi().fgBright(Ansi.Color.BLUE).a(s).reset().toString();
                         }
diff --git a/tooling/camel-util-json/src/main/java/org/apache/camel/util/json/Jsoner.java b/tooling/camel-util-json/src/main/java/org/apache/camel/util/json/Jsoner.java
index 573fe7eb484..1abb19d7af5 100644
--- a/tooling/camel-util-json/src/main/java/org/apache/camel/util/json/Jsoner.java
+++ b/tooling/camel-util-json/src/main/java/org/apache/camel/util/json/Jsoner.java
@@ -72,6 +72,12 @@ public final class Jsoner {
          * deserialize.
          */
         ALLOW_INVALIDS,
+        /**
+         * Instead of aborting serialization on non-JSON values it will do nothing and continue serialization by
+         * serializing the non-JSON value directly into the now invalid JSON. Be mindful that invalid JSON will not
+         * successfully deserialize.
+         */
+        ALLOW_INVALIDS_NOOP,
         /**
          * Instead of aborting serialization on non-JSON values that implement Jsonable it will continue serialization
          * by deferring serialization to the Jsonable.
@@ -862,6 +868,32 @@ public final class Jsoner {
         return writableDestination.toString();
     }
 
+    /**
+     * A convenience method that assumes a StringWriter.
+     *
+     * @param  jsonSerializable         represents the object that should be serialized as a string in JSON format.
+     * @return                          a string, in JSON format, that represents the object provided, or <tt>null</tt>
+     *                                  if not possible to serialize.
+     * @throws IllegalArgumentException if the jsonSerializable isn't serializable in JSON.
+     * @see                             Jsoner#serialize(Object, Writer)
+     * @see                             StringWriter
+     */
+    public static String trySerialize(final Object jsonSerializable) {
+        final StringWriter writableDestination = new StringWriter();
+        try {
+            Jsoner.serialize(jsonSerializable, writableDestination,
+                    EnumSet.of(SerializationOptions.ALLOW_JSONABLES, SerializationOptions.ALLOW_FULLY_QUALIFIED_ENUMERATIONS,
+                            SerializationOptions.ALLOW_INVALIDS_NOOP));
+        } catch (final IOException caught) {
+            /* See StringWriter. */
+        }
+        String answer = writableDestination.toString();
+        if ("SerializationOptions.ALLOW_INVALIDS_NOOP".equals(answer)) {
+            answer = null;
+        }
+        return answer;
+    }
+
     /**
      * Serializes values according to the RFC 4627 JSON specification. It will also trust the serialization provided by
      * any Jsonables it serializes and serializes Enums that don't implement Jsonable as a string of their fully
@@ -1116,7 +1148,10 @@ public final class Jsoner {
              * It cannot by any measure be safely serialized according to
              * specification.
              */
-            if (flags.contains(SerializationOptions.ALLOW_INVALIDS)) {
+            if (flags.contains(SerializationOptions.ALLOW_INVALIDS_NOOP)) {
+                // noop marker
+                writableDestination.write("SerializationOptions.ALLOW_INVALIDS_NOOP");
+            } else if (flags.contains(SerializationOptions.ALLOW_INVALIDS)) {
                 /* Can be helpful for debugging how it isn't valid. */
                 writableDestination.write(jsonSerializable.toString());
             } else {
diff --git a/tooling/camel-util-json/src/test/java/org/apache/camel/util/json/JSonerTest.java b/tooling/camel-util-json/src/test/java/org/apache/camel/util/json/JSonerTest.java
new file mode 100644
index 00000000000..fb7754cf092
--- /dev/null
+++ b/tooling/camel-util-json/src/test/java/org/apache/camel/util/json/JSonerTest.java
@@ -0,0 +1,41 @@
+/*
+ * 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.util.json;
+
+import java.util.Date;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class JSonerTest {
+
+    @Test
+    public void testTrySerialize() throws Exception {
+        String s = Jsoner.trySerialize("Hello World");
+        Assertions.assertEquals("\"Hello World\"", s);
+
+        s = Jsoner.trySerialize(123);
+        Assertions.assertEquals("123", s);
+
+        s = Jsoner.trySerialize(true);
+        Assertions.assertEquals("true", s);
+
+        s = Jsoner.trySerialize(new Date());
+        Assertions.assertNull(s);
+
+    }
+}