This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch standby in repository https://gitbox.apache.org/repos/asf/camel.git
commit d7f0148e17054affa8f5636a9ac38f5b3dae6726 Author: Claus Ibsen <[email protected]> AuthorDate: Sat Aug 31 17:40:15 2024 +0200 CAMEL-21150: camel-jbang - Make tracer in standby as default --- .../modules/ROOT/pages/camel-jbang.adoc | 37 +++++- .../core/commands/action/CamelTraceAction.java | 137 ++++++++++++++++++--- 2 files changed, 157 insertions(+), 17 deletions(-) diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc b/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc index da83b483961..1a201c620f6 100644 --- a/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc +++ b/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc @@ -1611,20 +1611,51 @@ command but only display message tracing information. This allows you to see eve The `trace` command has many options and can be used to _filter_, _grep_ or output on different detail _levels`. The _exchange id_ is logged (and grouped by colour), so you can use that to correlate the events, when traces are interleaved. -For example if an existing integration is running named chuck, you can trace it as follows: +The trace command will by default list the status of whether tracing is enabled or not in the integrations: [source,bash] ---- -camel trace chuck +camel trace + PID NAME AGE STATUS TOTAL QUEUE FILTER PATTERN + 6911 chuck 5s Standby 0 0 +---- + +Here we can see that the tracer is in standby mode, and you need to start the tracer before Camel will capture messages: + +TIP: Camel 4.8 onwards has tracing in standby mode (when using dev profile). You can enable tracing on startup by setting the configuration `camel.trace.enabled=true` in `application.properties`. + +[source,bash] +---- +camel trace --action=start ---- -You can also trace all running integrations +And if you run `camel trace` again you can see the tracer is started: [source,bash] ---- camel trace +PID NAME AGE STATUS TOTAL QUEUE FILTER PATTERN +6911 chuck 1m5s Started 16 4 ---- +And to show the traces you need to use the `dump` action as follows: + +[source,bash] +---- +camel trace chuck --action=dump +---- + +You can also dump traces from all running integrations: + +[source,bash] +---- +camel trace --action=dump +---- + +To stop tracing use `--action=stop`. + +And you can also clear the already traced messages with `--action=clear`. + ==== Running Camel integrations in background The `run` command allows to run Camel in the background with the `--background` option. diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelTraceAction.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelTraceAction.java index cedef90f181..63390605947 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelTraceAction.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelTraceAction.java @@ -23,6 +23,7 @@ import java.io.LineNumberReader; import java.text.SimpleDateFormat; import java.util.ArrayDeque; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -35,9 +36,15 @@ import java.util.Set; import java.util.concurrent.ArrayBlockingQueue; import java.util.regex.Pattern; +import com.github.freva.asciitable.AsciiTable; +import com.github.freva.asciitable.Column; +import com.github.freva.asciitable.HorizontalAlign; +import com.github.freva.asciitable.OverflowBehaviour; import org.apache.camel.catalog.impl.TimePatternConverter; import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain; +import org.apache.camel.dsl.jbang.core.common.PidNameAgeCompletionCandidates; import org.apache.camel.dsl.jbang.core.common.ProcessHelper; +import org.apache.camel.util.FileUtil; import org.apache.camel.util.IOHelper; import org.apache.camel.util.StopWatch; import org.apache.camel.util.StringHelper; @@ -75,17 +82,21 @@ public class CamelTraceAction extends ActionBaseCommand { @Override public Iterator<String> iterator() { - return List.of("start", "stop", "status").iterator(); + return List.of("dump", "start", "stop", "status", "clear").iterator(); } } @CommandLine.Parameters(description = "Name or pid of running Camel integration. (default selects all)", arity = "0..1") String name = "*"; - @CommandLine.Option(names = { "--action" }, completionCandidates = ActionCompletionCandidates.class, - description = "Action for start, stop, or show status of tracing") + @CommandLine.Option(names = { "--action" }, completionCandidates = ActionCompletionCandidates.class, defaultValue = "status", + description = "Action to start, stop, clear, list status, or dump traces") String action; + @CommandLine.Option(names = { "--sort" }, completionCandidates = PidNameAgeCompletionCandidates.class, + description = "Sort by pid, name or age for showing status of tracing", defaultValue = "pid") + String sort; + @CommandLine.Option(names = { "--timestamp" }, defaultValue = "true", description = "Print timestamp.") boolean timestamp = true; @@ -180,21 +191,30 @@ public class CamelTraceAction extends ActionBaseCommand { super(main); } - protected Integer doActionCall() throws Exception { - List<Long> pids = findPids(name); + @Override + public Integer doCall() throws Exception { + if ("dump".equals(action)) { + return doDumpCall(); + } else if ("status".equals(action)) { + return doStatusCall(); + } - if ("status".equals(action)) { - // TODO: show table of trace status per pid (like processor status) - } else { - for (long pid : pids) { + List<Long> pids = findPids(name); + for (long pid : pids) { + if ("clear".equals(action)) { + File f = getTraceFile("" + pid); + if (f.exists()) { + IOHelper.writeText("{}", f); + } + } else { JsonObject root = new JsonObject(); root.put("action", "trace"); - File f = getActionFile(Long.toString(pid)); if ("start".equals(action)) { root.put("enabled", "true"); } else if ("stop".equals(action)) { root.put("enabled", "false"); } + File f = getActionFile(Long.toString(pid)); IOHelper.writeText(root.toJson(), f); } } @@ -202,12 +222,88 @@ public class CamelTraceAction extends ActionBaseCommand { return 0; } - @Override - public Integer doCall() throws Exception { - if (action != null) { - return doActionCall(); + protected Integer doStatusCall() { + List<StatusRow> rows = new ArrayList<>(); + + List<Long> pids = findPids(name); + ProcessHandle.allProcesses() + .filter(ph -> pids.contains(ph.pid())) + .forEach(ph -> { + JsonObject root = loadStatus(ph.pid()); + if (root != null) { + StatusRow row = new StatusRow(); + JsonObject context = (JsonObject) root.get("context"); + if (context == null) { + return; + } + row.name = context.getString("name"); + if ("CamelJBang".equals(row.name)) { + row.name = ProcessHelper.extractName(root, ph); + } + row.pid = Long.toString(ph.pid()); + row.uptime = extractSince(ph); + row.age = TimeUtils.printSince(row.uptime); + JsonObject jo = root.getMap("trace"); + if (jo != null) { + row.enabled = jo.getBoolean("enabled"); + row.standby = jo.getBoolean("standby"); + row.counter = jo.getLong("counter"); + row.queueSize = jo.getLong("queueSize"); + row.filter = jo.getString("traceFilter"); + row.pattern = jo.getString("tracePattern"); + } + rows.add(row); + } + }); + + // sort rows + rows.sort(this::sortStatusRow); + + if (!rows.isEmpty()) { + printer().println(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), + new Column().header("AGE").headerAlign(HorizontalAlign.CENTER).with(r -> r.age), + new Column().header("STATUS").with(this::getTraceStatus), + new Column().header("TOTAL").with(r -> "" + r.counter), + new Column().header("QUEUE").with(r -> "" + r.queueSize), + new Column().header("FILTER").with(r -> r.filter), + new Column().header("PATTERN").with(r -> r.pattern)))); } + return 0; + } + + private String getTraceStatus(StatusRow r) { + if (r.enabled) { + return "Started"; + } else if (r.standby) { + return "Standby"; + } + return "Stopped"; + } + + protected int sortStatusRow(StatusRow o1, StatusRow o2) { + String s = sort; + int negate = 1; + if (s.startsWith("-")) { + s = s.substring(1); + negate = -1; + } + switch (s) { + case "pid": + return Long.compare(Long.parseLong(o1.pid), Long.parseLong(o2.pid)) * negate; + case "name": + return o1.name.compareToIgnoreCase(o2.name) * negate; + case "age": + return Long.compare(o1.uptime, o2.uptime) * negate; + default: + return 0; + } + } + + protected Integer doDumpCall() throws Exception { // setup table helper tableHelper = new MessageTableHelper(); tableHelper.setPretty(pretty); @@ -866,4 +962,17 @@ public class CamelTraceAction extends ActionBaseCommand { } + private static class StatusRow { + String pid; + String name; + String age; + long uptime; + boolean enabled; + boolean standby; + long counter; + long queueSize; + String filter; + String pattern; + } + }
