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 ad1effe57cdc019a017348e17ae969d76b448d8e
Author: Claus Ibsen <claus.ib...@gmail.com>
AuthorDate: Mon Aug 22 13:24:45 2022 +0200

    CAMEL-18406: camel-jbang - Status command
---
 .../camel/impl/console/ContextDevConsole.java      |   5 +-
 .../dsl/jbang/core/commands/CamelCommand.java      |  11 ++-
 .../dsl/jbang/core/commands/CamelJBangMain.java    |   2 +
 .../apache/camel/dsl/jbang/core/commands/Run.java  |  33 ++++++-
 .../jbang/core/commands/process/CamelStatus.java   | 102 +++++++++++++++++++++
 5 files changed, 144 insertions(+), 9 deletions(-)

diff --git 
a/core/camel-console/src/main/java/org/apache/camel/impl/console/ContextDevConsole.java
 
b/core/camel-console/src/main/java/org/apache/camel/impl/console/ContextDevConsole.java
index 4519ae69d57..5ae52f460fc 100644
--- 
a/core/camel-console/src/main/java/org/apache/camel/impl/console/ContextDevConsole.java
+++ 
b/core/camel-console/src/main/java/org/apache/camel/impl/console/ContextDevConsole.java
@@ -34,8 +34,8 @@ public class ContextDevConsole extends AbstractDevConsole {
     protected String doCallText(Map<String, Object> options) {
         StringBuilder sb = new StringBuilder();
 
-        sb.append(String.format("Apache Camel %s (%s) uptime %s", 
getCamelContext().getVersion(), getCamelContext().getName(),
-                getCamelContext().getUptime()));
+        sb.append(String.format("Apache Camel %s %s (%s) uptime %s", 
getCamelContext().getVersion(),
+                getCamelContext().getStatus().statusLowerCase(), 
getCamelContext().getName(), getCamelContext().getUptime()));
         sb.append("\n");
 
         ManagedCamelContext mcc = 
getCamelContext().getExtension(ManagedCamelContext.class);
@@ -57,6 +57,7 @@ public class ContextDevConsole extends AbstractDevConsole {
         JsonObject root = new JsonObject();
         root.put("name", getCamelContext().getName());
         root.put("version", getCamelContext().getVersion());
+        root.put("state", getCamelContext().getStatus());
         root.put("uptime", getCamelContext().getUptime());
 
         ManagedCamelContext mcc = 
getCamelContext().getExtension(ManagedCamelContext.class);
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelCommand.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelCommand.java
index caa1c6f2ee9..d89a4446a24 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelCommand.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelCommand.java
@@ -16,15 +16,15 @@
  */
 package org.apache.camel.dsl.jbang.core.commands;
 
+import java.io.File;
 import java.util.concurrent.Callable;
 
 import picocli.CommandLine;
 
 public abstract class CamelCommand implements Callable<Integer> {
 
-    public static final String PID_DIR = "${sys:user.home}/.camel";
-
     private final CamelJBangMain main;
+    private File camelDir;
 
     //CHECKSTYLE:OFF
     @CommandLine.Option(names = { "-h", "--help" }, usageHelp = true, 
description = "Display the help and sub-commands")
@@ -39,4 +39,11 @@ public abstract class CamelCommand implements 
Callable<Integer> {
         return main;
     }
 
+    public File getStatusFile(String pid) {
+        if (camelDir == null) {
+            camelDir = new File(System.getProperty("user.home"), ".camel");
+        }
+        return new File(camelDir, pid + "-status.json");
+    }
+
 }
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 9d404805843..8dfe2bf9373 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
@@ -20,6 +20,7 @@ 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.CamelStatus;
 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;
@@ -37,6 +38,7 @@ public class CamelJBangMain implements Callable<Integer> {
                 .addSubcommand("run", new CommandLine(new Run(main)))
                 .addSubcommand("ps", new CommandLine(new ListProcess(main)))
                 .addSubcommand("stop", new CommandLine(new StopProcess(main)))
+                .addSubcommand("status", new CommandLine(new 
CamelStatus(main)))
                 .addSubcommand("init", new CommandLine(new Init(main)))
                 .addSubcommand("bind", new CommandLine(new Bind(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/Run.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java
index 618db4f344b..3359aa06810 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java
@@ -48,6 +48,8 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 import io.apicurio.datamodels.Library;
 import io.apicurio.datamodels.openapi.models.OasDocument;
 import org.apache.camel.CamelContext;
+import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.console.DevConsole;
 import org.apache.camel.dsl.jbang.core.common.RuntimeUtil;
 import org.apache.camel.generator.openapi.RestDslGenerator;
 import org.apache.camel.impl.lw.LightweightCamelContext;
@@ -59,6 +61,7 @@ import org.apache.camel.util.FileUtil;
 import org.apache.camel.util.IOHelper;
 import org.apache.camel.util.ObjectHelper;
 import org.apache.camel.util.StringHelper;
+import org.apache.camel.util.json.JsonObject;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.core.config.Configurator;
 import picocli.CommandLine;
@@ -90,6 +93,7 @@ class Run extends CamelCommand {
 
     private CamelContext context;
     private File lockFile;
+    private File statusFile;
     private ScheduledExecutorService executor;
     private boolean silentRun;
     private boolean pipeRun;
@@ -241,6 +245,9 @@ class Run extends CamelCommand {
         if (lockFile != null) {
             FileUtil.deleteFile(lockFile);
         }
+        if (statusFile != null) {
+            FileUtil.deleteFile(statusFile);
+        }
         return 0;
     }
 
@@ -400,13 +407,30 @@ class Run extends CamelCommand {
         writeSetting(main, profileProperties, "camel.jbang.jfr-profile", 
jfrProfile != null ? jfrProfile : null);
 
         if (fileLock) {
-            lockFile = createLockFile();
+            lockFile = createLockFile(getPid());
+            if (lockFile != null) {
+                statusFile = createLockFile(lockFile.getName() + 
"-status.json");
+            }
             // to trigger shutdown on file lock deletion
             executor = Executors.newSingleThreadScheduledExecutor();
             executor.scheduleWithFixedDelay(() -> {
                 // if the lock file is deleted then stop
                 if (!lockFile.exists()) {
                     context.stop();
+                    return;
+                }
+                // update status file with details from the context console
+                try {
+                    DevConsole dc = 
main.getCamelContext().adapt(ExtendedCamelContext.class)
+                            
.getDevConsoleResolver().resolveDevConsole("context");
+                    if (dc != null) {
+                        JsonObject json = (JsonObject) 
dc.call(DevConsole.MediaType.JSON);
+                        if (json != null) {
+                            IOHelper.writeText(json.toJson(), statusFile);
+                        }
+                    }
+                } catch (Throwable e) {
+                    // ignore
                 }
             }, 1000, 1000, TimeUnit.MILLISECONDS);
         }
@@ -687,14 +711,13 @@ class Run extends CamelCommand {
         }
     }
 
-    public File createLockFile() throws IOException {
+    public File createLockFile(String name) {
         File answer = null;
-        String pid = getPid();
-        if (pid != null) {
+        if (name != null) {
             File dir = new File(System.getProperty("user.home"), ".camel");
             try {
                 dir.mkdirs();
-                answer = new File(dir, pid);
+                answer = new File(dir, name);
                 if (!answer.exists()) {
                     answer.createNewFile();
                 }
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelStatus.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelStatus.java
new file mode 100644
index 00000000000..f8678efdf0e
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelStatus.java
@@ -0,0 +1,102 @@
+/*
+ * 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.io.File;
+import java.io.FileInputStream;
+import java.math.BigDecimal;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.util.IOHelper;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.TimeUtils;
+import org.apache.camel.util.json.JsonObject;
+import org.apache.camel.util.json.Jsoner;
+import picocli.CommandLine;
+import picocli.CommandLine.Command;
+
+@Command(name = "status", description = "List status of the running Camel 
applications")
+public class CamelStatus extends ProcessBaseCommand {
+
+    @CommandLine.Option(names = { "--sort" },
+                        description = "Sort by pid, name or age", defaultValue 
= "pid")
+    String sort;
+
+    public CamelStatus(CamelJBangMain main) {
+        super(main);
+    }
+
+    @Override
+    public Integer call() throws Exception {
+        ProcessHandle.allProcesses()
+                .sorted((o1, o2) -> {
+                    switch (sort) {
+                        case "pid":
+                            return Long.compare(o1.pid(), o2.pid());
+                        case "name":
+                            return extractName(o1).compareTo(extractName(o2));
+                        case "age":
+                            // we want newest in top
+                            return Long.compare(extractSince(o1), 
extractSince(o2)) * -1;
+                        default:
+                            return 0;
+                    }
+                })
+                .forEach(ph -> {
+                    String name = extractName(ph);
+                    if (ObjectHelper.isNotEmpty(name)) {
+                        String ago = TimeUtils.printSince(extractSince(ph));
+                        JsonObject status = loadStatus(ph.pid());
+                        if (status != null) {
+                            String state = 
status.getString("state").toLowerCase(Locale.ROOT);
+                            Map<String, ?> stats = status.getMap("statistics");
+                            if (stats != null) {
+                                BigDecimal total = (BigDecimal) 
stats.get("exchangesTotal");
+                                BigDecimal inflight = (BigDecimal) 
stats.get("exchangesInflight");
+                                BigDecimal failed = (BigDecimal) 
stats.get("exchangesFailed");
+                                System.out.printf("%s camel run %s %s (age: 
%s, total: %s, inflight: %s, failed: %s)%n",
+                                        ph.pid(), name, state, ago, total, 
inflight, failed);
+                            } else {
+                                System.out.printf("%s camel run %s %s (age: 
%s)%n",
+                                        ph.pid(), name, state, ago);
+                            }
+                        } else {
+                            System.out.println(ph.pid() + " camel run " + name 
+ " (age: " + ago + ")");
+                        }
+                    }
+                });
+        return 0;
+    }
+
+    private JsonObject loadStatus(long pid) {
+        try {
+            File f = getStatusFile("" + pid);
+            if (f != null) {
+                FileInputStream fis = new FileInputStream(f);
+                String text = IOHelper.loadText(fis);
+                IOHelper.close(fis);
+                return (JsonObject) Jsoner.deserialize(text);
+            }
+        } catch (Throwable e) {
+            // ignore
+        }
+        return null;
+    }
+
+}

Reply via email to