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 2022/08/29 12:57:41 UTC

[camel] branch main updated (881588fc809 -> 90a5863a761)

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 881588fc809 Do wait for started before running the test
     new 471a17fc989 CAMEL-18425: camel-cli - Display more information for top commands.
     new 90a5863a761 CAMEL-18425: camel-cli - Display more information for top commands.

The 2 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:
 .../GarbageCollectorDevConsoleConfigurer.java      |  49 +++++
 .../impl/console/ThreadDevConsoleConfigurer.java   |  49 +++++
 ...e.camel.impl.console.GarbageCollectorDevConsole |   2 +
 .../org.apache.camel.impl.console.ThreadDevConsole |   2 +
 .../services/org/apache/camel/dev-console/gc       |   2 +
 .../services/org/apache/camel/dev-console/thread   |   2 +
 .../impl/console/GarbageCollectorDevConsole.java   |  73 +++++++
 .../camel/impl/console/ThreadDevConsole.java       | 101 ++++++++++
 .../modules/ROOT/pages/camel-jbang.adoc            |  36 +++-
 .../camel/cli/connector/LocalCliConnector.java     |  84 +++++++-
 .../dsl/jbang/core/commands/CamelJBangMain.java    |  10 +-
 .../core/commands/process/CamelContextTop.java     | 222 +++++++++++++++++++++
 .../{CamelTopStatus.java => CamelRouteTop.java}    |   6 +-
 .../process/{CamelTopStatus.java => CamelTop.java} |  26 +--
 14 files changed, 640 insertions(+), 24 deletions(-)
 create mode 100644 core/camel-console/src/generated/java/org/apache/camel/impl/console/GarbageCollectorDevConsoleConfigurer.java
 create mode 100644 core/camel-console/src/generated/java/org/apache/camel/impl/console/ThreadDevConsoleConfigurer.java
 create mode 100644 core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/configurer/org.apache.camel.impl.console.GarbageCollectorDevConsole
 create mode 100644 core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/configurer/org.apache.camel.impl.console.ThreadDevConsole
 create mode 100644 core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/dev-console/gc
 create mode 100644 core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/dev-console/thread
 create mode 100644 core/camel-console/src/main/java/org/apache/camel/impl/console/GarbageCollectorDevConsole.java
 create mode 100644 core/camel-console/src/main/java/org/apache/camel/impl/console/ThreadDevConsole.java
 create mode 100644 dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelContextTop.java
 copy dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/{CamelTopStatus.java => CamelRouteTop.java} (89%)
 rename dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/{CamelTopStatus.java => CamelTop.java} (62%)


[camel] 01/02: CAMEL-18425: camel-cli - Display more information for top commands.

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 471a17fc9890a4d19fabc6592184a1c54b689ae6
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon Aug 29 14:20:51 2022 +0200

    CAMEL-18425: camel-cli - Display more information for top commands.
---
 .../GarbageCollectorDevConsoleConfigurer.java      |  49 +++++
 .../impl/console/ThreadDevConsoleConfigurer.java   |  49 +++++
 ...e.camel.impl.console.GarbageCollectorDevConsole |   2 +
 .../org.apache.camel.impl.console.ThreadDevConsole |   2 +
 .../services/org/apache/camel/dev-console/gc       |   2 +
 .../services/org/apache/camel/dev-console/thread   |   2 +
 .../impl/console/GarbageCollectorDevConsole.java   |  73 +++++++
 .../camel/impl/console/ThreadDevConsole.java       | 101 ++++++++++
 .../camel/cli/connector/LocalCliConnector.java     |  84 +++++++-
 .../dsl/jbang/core/commands/CamelJBangMain.java    |  10 +-
 .../core/commands/process/CamelContextTop.java     | 222 +++++++++++++++++++++
 .../{CamelTopStatus.java => CamelRouteTop.java}    |   6 +-
 .../process/{CamelTopStatus.java => CamelTop.java} |  26 +--
 13 files changed, 605 insertions(+), 23 deletions(-)

diff --git a/core/camel-console/src/generated/java/org/apache/camel/impl/console/GarbageCollectorDevConsoleConfigurer.java b/core/camel-console/src/generated/java/org/apache/camel/impl/console/GarbageCollectorDevConsoleConfigurer.java
new file mode 100644
index 00000000000..6e11e40485e
--- /dev/null
+++ b/core/camel-console/src/generated/java/org/apache/camel/impl/console/GarbageCollectorDevConsoleConfigurer.java
@@ -0,0 +1,49 @@
+/* Generated by camel build tools - do NOT edit this file! */
+package org.apache.camel.impl.console;
+
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.spi.ExtendedPropertyConfigurerGetter;
+import org.apache.camel.spi.PropertyConfigurerGetter;
+import org.apache.camel.spi.ConfigurerStrategy;
+import org.apache.camel.spi.GeneratedPropertyConfigurer;
+import org.apache.camel.util.CaseInsensitiveMap;
+import org.apache.camel.impl.console.GarbageCollectorDevConsole;
+
+/**
+ * Generated by camel build tools - do NOT edit this file!
+ */
+@SuppressWarnings("unchecked")
+public class GarbageCollectorDevConsoleConfigurer extends org.apache.camel.support.component.PropertyConfigurerSupport implements GeneratedPropertyConfigurer, PropertyConfigurerGetter {
+
+    @Override
+    public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) {
+        org.apache.camel.impl.console.GarbageCollectorDevConsole target = (org.apache.camel.impl.console.GarbageCollectorDevConsole) obj;
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "camelcontext":
+        case "CamelContext": target.setCamelContext(property(camelContext, org.apache.camel.CamelContext.class, value)); return true;
+        default: return false;
+        }
+    }
+
+    @Override
+    public Class<?> getOptionType(String name, boolean ignoreCase) {
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "camelcontext":
+        case "CamelContext": return org.apache.camel.CamelContext.class;
+        default: return null;
+        }
+    }
+
+    @Override
+    public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
+        org.apache.camel.impl.console.GarbageCollectorDevConsole target = (org.apache.camel.impl.console.GarbageCollectorDevConsole) obj;
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "camelcontext":
+        case "CamelContext": return target.getCamelContext();
+        default: return null;
+        }
+    }
+}
+
diff --git a/core/camel-console/src/generated/java/org/apache/camel/impl/console/ThreadDevConsoleConfigurer.java b/core/camel-console/src/generated/java/org/apache/camel/impl/console/ThreadDevConsoleConfigurer.java
new file mode 100644
index 00000000000..6df6dd7ab60
--- /dev/null
+++ b/core/camel-console/src/generated/java/org/apache/camel/impl/console/ThreadDevConsoleConfigurer.java
@@ -0,0 +1,49 @@
+/* Generated by camel build tools - do NOT edit this file! */
+package org.apache.camel.impl.console;
+
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.spi.ExtendedPropertyConfigurerGetter;
+import org.apache.camel.spi.PropertyConfigurerGetter;
+import org.apache.camel.spi.ConfigurerStrategy;
+import org.apache.camel.spi.GeneratedPropertyConfigurer;
+import org.apache.camel.util.CaseInsensitiveMap;
+import org.apache.camel.impl.console.ThreadDevConsole;
+
+/**
+ * Generated by camel build tools - do NOT edit this file!
+ */
+@SuppressWarnings("unchecked")
+public class ThreadDevConsoleConfigurer extends org.apache.camel.support.component.PropertyConfigurerSupport implements GeneratedPropertyConfigurer, PropertyConfigurerGetter {
+
+    @Override
+    public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) {
+        org.apache.camel.impl.console.ThreadDevConsole target = (org.apache.camel.impl.console.ThreadDevConsole) obj;
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "camelcontext":
+        case "CamelContext": target.setCamelContext(property(camelContext, org.apache.camel.CamelContext.class, value)); return true;
+        default: return false;
+        }
+    }
+
+    @Override
+    public Class<?> getOptionType(String name, boolean ignoreCase) {
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "camelcontext":
+        case "CamelContext": return org.apache.camel.CamelContext.class;
+        default: return null;
+        }
+    }
+
+    @Override
+    public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
+        org.apache.camel.impl.console.ThreadDevConsole target = (org.apache.camel.impl.console.ThreadDevConsole) obj;
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "camelcontext":
+        case "CamelContext": return target.getCamelContext();
+        default: return null;
+        }
+    }
+}
+
diff --git a/core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/configurer/org.apache.camel.impl.console.GarbageCollectorDevConsole b/core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/configurer/org.apache.camel.impl.console.GarbageCollectorDevConsole
new file mode 100644
index 00000000000..da5eb35d631
--- /dev/null
+++ b/core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/configurer/org.apache.camel.impl.console.GarbageCollectorDevConsole
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.impl.console.GarbageCollectorDevConsoleConfigurer
diff --git a/core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/configurer/org.apache.camel.impl.console.ThreadDevConsole b/core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/configurer/org.apache.camel.impl.console.ThreadDevConsole
new file mode 100644
index 00000000000..6aff17f333c
--- /dev/null
+++ b/core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/configurer/org.apache.camel.impl.console.ThreadDevConsole
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.impl.console.ThreadDevConsoleConfigurer
diff --git a/core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/dev-console/gc b/core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/dev-console/gc
new file mode 100644
index 00000000000..b3f7a71ee18
--- /dev/null
+++ b/core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/dev-console/gc
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.impl.console.GarbageCollectorDevConsole
diff --git a/core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/dev-console/thread b/core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/dev-console/thread
new file mode 100644
index 00000000000..e34acd483f6
--- /dev/null
+++ b/core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/dev-console/thread
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.impl.console.ThreadDevConsole
diff --git a/core/camel-console/src/main/java/org/apache/camel/impl/console/GarbageCollectorDevConsole.java b/core/camel-console/src/main/java/org/apache/camel/impl/console/GarbageCollectorDevConsole.java
new file mode 100644
index 00000000000..9e2bdc6ee3a
--- /dev/null
+++ b/core/camel-console/src/main/java/org/apache/camel/impl/console/GarbageCollectorDevConsole.java
@@ -0,0 +1,73 @@
+/*
+ * 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.impl.console;
+
+import org.apache.camel.spi.Configurer;
+import org.apache.camel.spi.annotations.DevConsole;
+import org.apache.camel.util.json.JsonArray;
+import org.apache.camel.util.json.JsonObject;
+
+import java.lang.management.GarbageCollectorMXBean;
+import java.lang.management.ManagementFactory;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import static org.apache.camel.util.UnitUtils.printUnitFromBytesDot;
+
+@DevConsole("gc")
+@Configurer(bootstrap = true)
+public class GarbageCollectorDevConsole extends AbstractDevConsole {
+
+    public GarbageCollectorDevConsole() {
+        super("jvm", "gc", "Garbage Collector", "Displays Garbage Collector information");
+    }
+
+    @Override
+    protected String doCallText(Map<String, Object> options) {
+        StringBuilder sb = new StringBuilder();
+
+        List<GarbageCollectorMXBean> gcs = ManagementFactory.getGarbageCollectorMXBeans();
+        if (gcs != null && !gcs.isEmpty()) {
+            for (GarbageCollectorMXBean gc : gcs) {
+                sb.append(String.format("\n    %s: %s (%s ms)", gc.getName(), gc.getCollectionCount(), gc.getCollectionTime()));
+            }
+        }
+
+        return sb.toString();
+    }
+
+    @Override
+    protected JsonObject doCallJson(Map<String, Object> options) {
+        JsonObject root = new JsonObject();
+        JsonArray arr = new JsonArray();
+        root.put("garbageCollectors", arr);
+
+        List<GarbageCollectorMXBean> gcs = ManagementFactory.getGarbageCollectorMXBeans();
+        if (gcs != null && !gcs.isEmpty()) {
+            for (GarbageCollectorMXBean gc : gcs) {
+                JsonObject jo = new JsonObject();
+                arr.add(jo);
+                jo.put("name", gc.getName());
+                jo.put("collectionCount", gc.getCollectionCount());
+                jo.put("collectionTime", gc.getCollectionTime());
+                jo.put("memoryPoolNames", String.join(",", Arrays.asList(gc.getMemoryPoolNames())));
+            }
+        }
+        return root;
+    }
+}
diff --git a/core/camel-console/src/main/java/org/apache/camel/impl/console/ThreadDevConsole.java b/core/camel-console/src/main/java/org/apache/camel/impl/console/ThreadDevConsole.java
new file mode 100644
index 00000000000..ed98ea22724
--- /dev/null
+++ b/core/camel-console/src/main/java/org/apache/camel/impl/console/ThreadDevConsole.java
@@ -0,0 +1,101 @@
+/*
+ * 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.impl.console;
+
+import org.apache.camel.spi.Configurer;
+import org.apache.camel.spi.annotations.DevConsole;
+import org.apache.camel.util.json.JsonArray;
+import org.apache.camel.util.json.JsonObject;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
+import java.util.Arrays;
+import java.util.Map;
+
+@DevConsole("thread")
+@Configurer(bootstrap = true)
+public class ThreadDevConsole extends AbstractDevConsole {
+
+    public ThreadDevConsole() {
+        super("jvm", "thread", "Thread", "Displays Threads information");
+    }
+
+    @Override
+    protected String doCallText(Map<String, Object> options) {
+        StringBuilder sb = new StringBuilder();
+
+        ThreadMXBean tb = ManagementFactory.getThreadMXBean();
+        if (tb != null) {
+            sb.append(String.format("Threads: %s\n", tb.getThreadCount()));
+            sb.append(String.format("Daemon Threads: %s\n", tb.getDaemonThreadCount()));
+            sb.append(String.format("Total Started Threads: %s\n", tb.getTotalStartedThreadCount()));
+            sb.append(String.format("Peak Threads: %s\n", tb.getPeakThreadCount()));
+
+            long[] ids = tb.getAllThreadIds();
+            Arrays.sort(ids);
+            for (long id : ids) {
+                ThreadInfo ti = tb.getThreadInfo(id);
+                if (ti != null) {
+                    String lock = ti.getLockName() != null ? "locked: " + ti.getLockName() : "";
+                    sb.append(String.format("\n    Thread %s: %s (%s) %s", id, ti.getThreadName(), ti.getThreadState(), lock));
+                }
+            }
+        }
+
+        return sb.toString();
+    }
+
+    @Override
+    protected JsonObject doCallJson(Map<String, Object> options) {
+        JsonObject root = new JsonObject();
+
+        ThreadMXBean tb = ManagementFactory.getThreadMXBean();
+        if (tb != null) {
+            root.put("threadCount", tb.getThreadCount());
+            root.put("daemonThreadCount", tb.getDaemonThreadCount());
+            root.put("totalStartedThreadCount", tb.getTotalStartedThreadCount());
+            root.put("peakThreadCount", tb.getPeakThreadCount());
+
+            JsonArray arr = new JsonArray();
+            root.put("threads", arr);
+
+            long[] ids = tb.getAllThreadIds();
+            Arrays.sort(ids);
+            for (long id : ids) {
+                ThreadInfo ti = tb.getThreadInfo(id);
+                if (ti != null) {
+                    JsonObject jo = new JsonObject();
+                    jo.put("id", ti.getThreadId());
+                    jo.put("name", ti.getThreadName());
+                    jo.put("state", ti.getThreadState());
+                    jo.put("blockedCount", ti.getBlockedCount());
+                    jo.put("blockedTime", ti.getBlockedTime());
+                    jo.put("waitedCount", ti.getWaitedCount());
+                    jo.put("waitedTime", ti.getWaitedTime());
+                    if (ti.getLockName() != null) {
+                        jo.put("lockName", ti.getLockName());
+                    }
+                    arr.add(jo);
+                }
+            }
+        }
+
+        return root;
+    }
+
+}
diff --git a/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/LocalCliConnector.java b/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/LocalCliConnector.java
index d51a7f79a27..f26d00b5afd 100644
--- a/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/LocalCliConnector.java
+++ b/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/LocalCliConnector.java
@@ -17,7 +17,14 @@
 package org.apache.camel.cli.connector;
 
 import java.io.File;
+import java.lang.management.ClassLoadingMXBean;
+import java.lang.management.GarbageCollectorMXBean;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryMXBean;
+import java.lang.management.RuntimeMXBean;
+import java.lang.management.ThreadMXBean;
 import java.util.Collection;
+import java.util.List;
 import java.util.Locale;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -168,11 +175,15 @@ public class LocalCliConnector extends ServiceSupport implements CliConnector, C
             ProcessHandle.current().info().user().ifPresent(u -> rc.put("user", u));
             rc.put("platform", platform);
             if (platformVersion != null) {
-                rc.put("version", platformVersion);
+                rc.put("platformVersion", platformVersion);
             }
             if (mainClass != null) {
                 rc.put("mainClass", mainClass);
             }
+            RuntimeMXBean mb = ManagementFactory.getRuntimeMXBean();
+            if (mb != null) {
+                rc.put("javaVersion", mb.getVmVersion());
+            }
             root.put("runtime", rc);
 
             // collect details via console
@@ -190,6 +201,23 @@ public class LocalCliConnector extends ServiceSupport implements CliConnector, C
                     root.put("routes", json2.get("routes"));
                 }
             }
+            // various details
+            JsonObject mem = collectMemory();
+            if (mem != null) {
+                root.put("memory", mem);
+            }
+            JsonObject cl = collectClassLoading();
+            if (cl != null) {
+                root.put("classLoading", cl);
+            }
+            JsonObject threads = collectThreads();
+            if (threads != null) {
+                root.put("threads", threads);
+            }
+            JsonObject gc = collectGC();
+            if (gc != null) {
+                root.put("gc", gc);
+            }
             // and health-check readiness
             Collection<HealthCheck.Result> res = HealthCheckHelper.invokeReadiness(camelContext);
             for (var r : res) {
@@ -213,6 +241,60 @@ public class LocalCliConnector extends ServiceSupport implements CliConnector, C
         }
     }
 
+    private JsonObject collectMemory() {
+        MemoryMXBean mb = ManagementFactory.getMemoryMXBean();
+        if (mb != null) {
+            JsonObject root = new JsonObject();
+            root.put("heapMemoryUsed", mb.getHeapMemoryUsage().getUsed());
+            root.put("heapMemoryCommitted", mb.getHeapMemoryUsage().getCommitted());
+            root.put("heapMemoryMax", mb.getHeapMemoryUsage().getMax());
+            root.put("nonHeapMemoryUsed", mb.getNonHeapMemoryUsage().getUsed());
+            root.put("nonHeapMemoryCommitted", mb.getNonHeapMemoryUsage().getCommitted());
+            return root;
+        }
+        return null;
+    }
+
+    private JsonObject collectClassLoading() {
+        ClassLoadingMXBean cb = ManagementFactory.getClassLoadingMXBean();
+        if (cb != null) {
+            JsonObject root = new JsonObject();
+            root.put("loadedClassCount", cb.getLoadedClassCount());
+            root.put("unloadedClassCount", cb.getUnloadedClassCount());
+            root.put("totalLoadedClassCount", cb.getTotalLoadedClassCount());
+            return root;
+        }
+        return null;
+    }
+
+    private JsonObject collectThreads() {
+        ThreadMXBean tb = ManagementFactory.getThreadMXBean();
+        if (tb != null) {
+            JsonObject root = new JsonObject();
+            root.put("threadCount", tb.getThreadCount());
+            root.put("peakThreadCount", tb.getPeakThreadCount());
+            return root;
+        }
+        return null;
+    }
+
+    private JsonObject collectGC() {
+        List<GarbageCollectorMXBean> gcs = ManagementFactory.getGarbageCollectorMXBeans();
+        if (gcs != null && !gcs.isEmpty()) {
+            JsonObject root = new JsonObject();
+            long count = 0;
+            long time = 0;
+            for (GarbageCollectorMXBean gc : gcs) {
+                count += gc.getCollectionCount();
+                time += gc.getCollectionTime();
+            }
+            root.put("collectionCount", count);
+            root.put("collectionTime", time);
+            return root;
+        }
+        return null;
+    }
+
     @Override
     protected void doStop() throws Exception {
         // cleanup
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
index e19a4f0f55f..32448d38b62 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
@@ -21,9 +21,11 @@ import java.util.concurrent.Callable;
 import org.apache.camel.catalog.CamelCatalog;
 import org.apache.camel.catalog.DefaultCamelCatalog;
 import org.apache.camel.dsl.jbang.core.commands.process.CamelContextStatus;
+import org.apache.camel.dsl.jbang.core.commands.process.CamelContextTop;
 import org.apache.camel.dsl.jbang.core.commands.process.CamelRouteStatus;
+import org.apache.camel.dsl.jbang.core.commands.process.CamelRouteTop;
 import org.apache.camel.dsl.jbang.core.commands.process.CamelStatus;
-import org.apache.camel.dsl.jbang.core.commands.process.CamelTopStatus;
+import org.apache.camel.dsl.jbang.core.commands.process.CamelTop;
 import org.apache.camel.dsl.jbang.core.commands.process.Hawtio;
 import org.apache.camel.dsl.jbang.core.commands.process.Jolokia;
 import org.apache.camel.dsl.jbang.core.commands.process.ListProcess;
@@ -44,8 +46,10 @@ public class CamelJBangMain implements Callable<Integer> {
                 .addSubcommand("stop", new CommandLine(new StopProcess(main)))
                 .addSubcommand("get", new CommandLine(new CamelStatus(main))
                         .addSubcommand("context", new CommandLine(new CamelContextStatus(main)))
-                        .addSubcommand("route", new CommandLine(new CamelRouteStatus(main)))
-                        .addSubcommand("top", new CommandLine(new CamelTopStatus(main))))
+                        .addSubcommand("route", new CommandLine(new CamelRouteStatus(main))))
+                .addSubcommand("top", new CommandLine(new CamelTop(main))
+                        .addSubcommand("context", new CommandLine(new CamelContextTop(main)))
+                        .addSubcommand("route", new CommandLine(new CamelRouteTop(main))))
                 .addSubcommand("generate", new CommandLine(new CodeGenerator(main))
                         .addSubcommand("rest", new CommandLine(new CodeRestGenerator(main))))
                 .addSubcommand("jolokia", new CommandLine(new Jolokia(main)))
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelContextTop.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelContextTop.java
new file mode 100644
index 00000000000..2c51d4acfa5
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelContextTop.java
@@ -0,0 +1,222 @@
+/*
+ * 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.commands.process;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+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.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.util.TimeUtils;
+import org.apache.camel.util.json.JsonObject;
+import picocli.CommandLine;
+import picocli.CommandLine.Command;
+
+@Command(name = "integration", aliases = { "int", "integration", "integrations", "context" },
+         description = "Top status of Camel integrations")
+public class CamelContextTop extends ProcessBaseCommand {
+
+    @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "0..1")
+    String name = "*";
+
+    @CommandLine.Option(names = { "--sort" },
+                        description = "Sort by pid, name, mem, or age", defaultValue = "mem")
+    String sort;
+
+    public CamelContextTop(CamelJBangMain main) {
+        super(main);
+    }
+
+    @Override
+    public Integer call() throws Exception {
+        List<Row> rows = new ArrayList<>();
+
+        List<Long> pids = findPids(name);
+        ProcessHandle.allProcesses()
+                .filter(ph -> pids.contains(ph.pid()))
+                .forEach(ph -> {
+                    JsonObject root = loadStatus(ph.pid());
+                    // there must be a status file for the running Camel integration
+                    if (root != null) {
+                        Row row = new Row();
+                        rows.add(row);
+                        row.name = extractName(root, ph);
+                        row.pid = "" + ph.pid();
+                        row.uptime = extractSince(ph);
+                        row.ago = TimeUtils.printSince(row.uptime);
+                        JsonObject runtime = (JsonObject) root.get("runtime");
+                        row.platform = extractPlatform(ph, runtime);
+                        row.platformVersion = runtime != null ? runtime.getString("platformVersion") : null;
+                        row.javaVersion = runtime != null ? runtime.getString("javaVersion") : null;
+                        JsonObject context = (JsonObject) root.get("context");
+                        row.state = context.getInteger("phase");
+                        row.camelVersion = context.getString("version");
+
+                        JsonObject mem = (JsonObject) root.get("memory");
+                        if (mem != null) {
+                            row.heapMemUsed = mem.getLong("heapMemoryUsed");
+                            row.heapMemCommitted = mem.getLong("heapMemoryCommitted");
+                            row.heapMemMax = mem.getLong("heapMemoryMax");
+                            row.nonHeapMemUsed = mem.getLong("nonHeapMemoryUsed");
+                            row.nonHeapMemCommitted = mem.getLong("nonHeapMemoryCommitted");
+                        }
+                        JsonObject threads = (JsonObject) root.get("threads");
+                        if (threads != null) {
+                            row.threadCount = threads.getInteger("threadCount");
+                            row.peakThreadCount = threads.getInteger("peakThreadCount");
+                        }
+                        JsonObject cl = (JsonObject) root.get("classLoading");
+                        if (cl != null) {
+                            row.loadedClassCount = cl.getInteger("loadedClassCount");
+                            row.totalLoadedClassCount = cl.getLong("totalLoadedClassCount");
+                        }
+                        JsonObject gc = (JsonObject) root.get("gc");
+                        if (gc != null) {
+                            row.gcCount = gc.getLong("collectionCount");
+                            row.gcTime = gc.getLong("collectionTime");
+                        }
+                    }
+                });
+
+        // sort rows
+        rows.sort(this::sortRow);
+
+        if (!rows.isEmpty()) {
+            System.out.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)
+                            .with(r -> r.name),
+                    new Column().header("JAVA").dataAlign(HorizontalAlign.LEFT).with(this::getJavaVersion),
+                    new Column().header("CAMEL").dataAlign(HorizontalAlign.LEFT).with(r -> r.camelVersion),
+                    new Column().header("PLATFORM").dataAlign(HorizontalAlign.LEFT).with(this::getPlatform),
+                    new Column().header("STATUS").headerAlign(HorizontalAlign.CENTER)
+                            .with(r -> extractState(r.state)),
+                    new Column().header("AGE").headerAlign(HorizontalAlign.CENTER).with(r -> r.ago),
+                    new Column().header("HEAP").headerAlign(HorizontalAlign.CENTER).with(this::getHeapMemory),
+                    new Column().header("NON-HEAP").headerAlign(HorizontalAlign.CENTER).with(this::getNonHeapMemory),
+                    new Column().header("GC").headerAlign(HorizontalAlign.CENTER).with(this::getGC),
+                    new Column().header("THREADS").headerAlign(HorizontalAlign.CENTER).with(this::getThreads),
+                    new Column().header("CLASSES").headerAlign(HorizontalAlign.CENTER).with(this::getClassLoading))));
+        }
+
+        return 0;
+    }
+
+    private String extractPlatform(ProcessHandle ph, JsonObject runtime) {
+        String answer = runtime != null ? runtime.getString("platform") : null;
+        if ("Camel".equals(answer)) {
+            // generic camel, we need to check if we run in JBang
+            String cl = ph.info().commandLine().orElse("");
+            if (cl.contains("main.CamelJBang run")) {
+                answer = "JBang";
+            }
+        }
+        return answer;
+    }
+
+    protected int sortRow(Row o1, Row o2) {
+        switch (sort) {
+            case "pid":
+                return Long.compare(Long.parseLong(o1.pid), Long.parseLong(o2.pid));
+            case "name":
+                return o1.name.compareToIgnoreCase(o2.name);
+            case "mem":
+                return Long.compare(o1.heapMemUsed, o2.heapMemUsed) * -1; // we want the biggest first
+            case "age":
+                return Long.compare(o1.uptime, o2.uptime);
+            default:
+                return 0;
+        }
+    }
+
+    private String getPlatform(Row r) {
+        if (r.platformVersion != null) {
+            return r.platform + " v" + r.platformVersion;
+        } else {
+            return r.platform;
+        }
+    }
+
+    private String getHeapMemory(Row r) {
+        return asMegaBytesOneDigit(r.heapMemUsed) + "/" + asMegaBytesOneDigit(r.heapMemCommitted) + "/"
+               + asMegaBytesOneDigit(r.heapMemMax) + " MB";
+    }
+
+    private String getNonHeapMemory(Row r) {
+        return asMegaBytesOneDigit(r.nonHeapMemUsed) + "/" + asMegaBytesOneDigit(r.nonHeapMemCommitted) + " MB";
+    }
+
+    private String getThreads(Row r) {
+        return r.threadCount + "/" + r.peakThreadCount;
+    }
+
+    private String getClassLoading(Row r) {
+        return r.loadedClassCount + "/" + r.totalLoadedClassCount;
+    }
+
+    private String getGC(Row r) {
+        if (r.gcTime <= 0) {
+            return "";
+        } else {
+            return r.gcTime + "ms (" + r.gcCount + ")";
+        }
+    }
+
+    private String getJavaVersion(Row r) {
+        String v = r.javaVersion;
+        for (int i = 0; i < v.length(); i++) {
+            char ch = v.charAt(i);
+            if (Character.isDigit(ch) || ch == '.') {
+                continue;
+            }
+            return v.substring(0, i);
+        }
+        return v;
+    }
+
+    private static long asMegaBytesOneDigit(long bytes) {
+        return bytes / 1000 / 1000;
+    }
+
+    private static class Row {
+        String pid;
+        String platform;
+        String platformVersion;
+        String camelVersion;
+        String javaVersion;
+        String name;
+        int state;
+        String ago;
+        long uptime;
+        long heapMemUsed;
+        long heapMemCommitted;
+        long heapMemMax;
+        long nonHeapMemUsed;
+        long nonHeapMemCommitted;
+        int threadCount;
+        int peakThreadCount;
+        int loadedClassCount;
+        long totalLoadedClassCount;
+        long gcCount;
+        long gcTime;
+    }
+
+}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelTopStatus.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelRouteTop.java
similarity index 89%
copy from dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelTopStatus.java
copy to dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelRouteTop.java
index 44d6e8a17ea..afef2e6bb1c 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelTopStatus.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelRouteTop.java
@@ -19,10 +19,10 @@ package org.apache.camel.dsl.jbang.core.commands.process;
 import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
 import picocli.CommandLine.Command;
 
-@Command(name = "top", description = "Top performing routes")
-public class CamelTopStatus extends CamelRouteStatus {
+@Command(name = "route", description = "Top performing routes")
+public class CamelRouteTop extends CamelRouteStatus {
 
-    public CamelTopStatus(CamelJBangMain main) {
+    public CamelRouteTop(CamelJBangMain main) {
         super(main);
     }
 
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelTopStatus.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelTop.java
similarity index 62%
rename from dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelTopStatus.java
rename to dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelTop.java
index 44d6e8a17ea..93c56715adf 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelTopStatus.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelTop.java
@@ -16,28 +16,22 @@
  */
 package org.apache.camel.dsl.jbang.core.commands.process;
 
+import org.apache.camel.dsl.jbang.core.commands.CamelCommand;
 import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
-import picocli.CommandLine.Command;
+import picocli.CommandLine;
 
-@Command(name = "top", description = "Top performing routes")
-public class CamelTopStatus extends CamelRouteStatus {
+@CommandLine.Command(name = "top",
+                     description = "Top status of Camel integrations (use --help to see sub commands)")
+public class CamelTop extends CamelCommand {
 
-    public CamelTopStatus(CamelJBangMain main) {
+    public CamelTop(CamelJBangMain main) {
         super(main);
     }
 
     @Override
-    protected int sortRow(Row o1, Row o2) {
-        // sort for highest mean value as we want the slowest in the top
-        long m1 = o1.mean != null ? Long.parseLong(o1.mean) : 0;
-        long m2 = o2.mean != null ? Long.parseLong(o2.mean) : 0;
-        if (m1 < m2) {
-            return 1;
-        } else if (m1 > m2) {
-            return -1;
-        } else {
-            return 0;
-        }
+    public Integer call() throws Exception {
+        // default to top the integrations
+        new CommandLine(new CamelRouteTop(getMain())).execute();
+        return 0;
     }
-
 }


[camel] 02/02: CAMEL-18425: camel-cli - Display more information for top commands.

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 90a5863a7611a47dd28ebc95754fece9b9aa5c8f
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon Aug 29 14:57:22 2022 +0200

    CAMEL-18425: camel-cli - Display more information for top commands.
---
 .../modules/ROOT/pages/camel-jbang.adoc            | 36 +++++++++++++++++++++-
 1 file changed, 35 insertions(+), 1 deletion(-)

diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc b/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
index 1aab8db4ca3..ac79fa7d447 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
@@ -614,7 +614,7 @@ the total number of messages processed. The column _Since Last_
 shows how long time ago the integration was active processing
 incoming messages.
 
-You can also see the status of every routes, from all the local Camel integrations:
+You can also see the status of every routes, from all the local Camel integrations with `camel get route`:
 
 [source,bash]
 ----
@@ -627,6 +627,40 @@ camel get route
 
 TIP: Use `camel get --help` to display all the available commands as additional will be added in upcoming releases.
 
+=== Top status of Camel integrations
+
+The `camel top` command is intended for getting top utilization statistics (highest to lowest heap used memory)
+of the running Camel integrations.
+
+[source,bash]
+----
+camel top
+  PID   NAME                          JAVA     CAMEL            PLATFORM            STATUS    AGE         HEAP        NON-HEAP     GC     THREADS   CLASSES
+ 22104  chuck.yaml                    11.0.13  3.19.0-SNAPSHOT  JBang               Running   2m10s  131/322/4294 MB  70/73 MB  17ms (6)      7/8  7456/7456
+ 14242  sample.camel.MyCamelApplica…  11.0.13  3.19.0-SNAPSHOT  Spring Boot v2.7.3  Running  33m40s  115/332/4294 MB  62/66 MB  37ms (6)    16/16  8428/8428
+ 22116  bar.yaml                      11.0.13  3.19.0-SNAPSHOT  JBang               Running    2m7s   33/268/4294 MB  54/58 MB  20ms (4)      7/8  6104/6104
+----
+
+The _HEAP_ column shows the heap memory (used/committed/max) and the non-heap (used/committed).
+The _GC_ column shows garbage collection information (time and total runs).
+The _CLASSES_ column shows number of classes (loaded/total).
+
+You can also see the top performing routes (highest to lowest mean processing time)
+of every routes, from all the local Camel integrations with `camel top route`:
+
+[source,bash]
+----
+camel top route
+  PID   NAME                          ID                     FROM                                 STATUS    AGE    TOTAL  FAILED  INFLIGHT  MEAN  MIN  MAX  SINCE-LAST
+ 22104  chuck.yaml                    chuck-norris-source-1  timer://chuck?period=10000           Started     10s      1       0         0   163  163  163          9s
+ 22116  bar.yaml                      route1                 timer://yaml2?period=1000            Started      7s      7       0         0     1    0   11          0s
+ 22104  chuck.yaml                    chuck                  kamelet://chuck-norris-source        Started     10s      1       0         0     0    0    0          9s
+ 22104  chuck.yaml                    log-sink-2             kamelet://source?routeId=log-sink-2  Started     10s      1       0         0     0    0    0          9s
+ 14242  sample.camel.MyCamelApplicat  hello                  timer://hello?period=2000            Started  31m41s    948       0         0     0    0    4          0s
+----
+
+TIP: Use `camel top --help` to display all the available commands as additional will be added in upcoming releases.
+
 
 === Using Jolokia and Hawtio