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


The following commit(s) were added to refs/heads/main by this push:
     new 3954f5c5d6c CAMEL-20474: camel-platform-http-main - Add /q/info to 
show some basic details
3954f5c5d6c is described below

commit 3954f5c5d6cfdde7204d3b837616c3181768cf3a
Author: Claus Ibsen <claus.ib...@gmail.com>
AuthorDate: Thu Feb 29 13:59:01 2024 +0100

    CAMEL-20474: camel-platform-http-main - Add /q/info to show some basic 
details
---
 .../main/camel-main-configuration-metadata.json    |   1 +
 .../http/main/DefaultMainHttpServerFactory.java    |   1 +
 .../platform/http/main/MainHttpServer.java         | 129 +++++++++++++++++++++
 ...ttpServerConfigurationPropertiesConfigurer.java |   6 +
 .../camel-main-configuration-metadata.json         |   1 +
 core/camel-main/src/main/docs/main.adoc            |   3 +-
 .../main/HttpServerConfigurationProperties.java    |  20 ++++
 .../modules/ROOT/pages/camel-jbang.adoc            |   3 +
 .../java/org/apache/camel/main/KameletMain.java    |   6 +
 9 files changed, 169 insertions(+), 1 deletion(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
index f2f63e72a4a..387d0a54077 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
@@ -253,6 +253,7 @@
     { "name": "camel.server.enabled", "description": "Whether embedded HTTP 
server is enabled. By default, the server is not enabled.", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "boolean", 
"javaType": "boolean", "defaultValue": "false" },
     { "name": "camel.server.healthCheckEnabled", "description": "Whether to 
enable health-check console. If enabled then you can access health-check status 
on context-path: \/q\/health", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "boolean", 
"javaType": "boolean", "defaultValue": "false" },
     { "name": "camel.server.host", "description": "Hostname to use for binding 
embedded HTTP server", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string", 
"javaType": "java.lang.String", "defaultValue": "0.0.0.0" },
+    { "name": "camel.server.infoEnabled", "description": "Whether to enable 
info console. If enabled then you can see some basic Camel information at 
\/q\/info", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "boolean", 
"javaType": "boolean", "defaultValue": "false" },
     { "name": "camel.server.jolokiaEnabled", "description": "Whether to enable 
jolokia. If enabled then you can access jolokia api on context-path: 
\/q\/jolokia", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "boolean", 
"javaType": "boolean", "defaultValue": "false" },
     { "name": "camel.server.maxBodySize", "description": "Maximum HTTP body 
size the embedded HTTP server can accept.", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "integer", 
"javaType": "java.lang.Long" },
     { "name": "camel.server.metricsEnabled", "description": "Whether to enable 
metrics. If enabled then you can access metrics on context-path: \/q\/metrics", 
"sourceType": "org.apache.camel.main.HttpServerConfigurationProperties", 
"type": "boolean", "javaType": "boolean", "defaultValue": "false" },
diff --git 
a/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/DefaultMainHttpServerFactory.java
 
b/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/DefaultMainHttpServerFactory.java
index 52e769b7b18..6e49fd94303 100644
--- 
a/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/DefaultMainHttpServerFactory.java
+++ 
b/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/DefaultMainHttpServerFactory.java
@@ -51,6 +51,7 @@ public class DefaultMainHttpServerFactory implements 
CamelContextAware, MainHttp
             server.setMaxBodySize(configuration.getMaxBodySize());
         }
         
server.setUseGlobalSslContextParameters(configuration.isUseGlobalSslContextParameters());
+        server.setInfoEnabled(configuration.isInfoEnabled());
         server.setDevConsoleEnabled(configuration.isDevConsoleEnabled());
         server.setHealthCheckEnabled(configuration.isHealthCheckEnabled());
         server.setJolokiaEnabled(configuration.isJolokiaEnabled());
diff --git 
a/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/MainHttpServer.java
 
b/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/MainHttpServer.java
index a3311f307a7..b0e1b1b5390 100644
--- 
a/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/MainHttpServer.java
+++ 
b/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/MainHttpServer.java
@@ -20,8 +20,11 @@ import java.io.File;
 import java.io.FileOutputStream;
 import java.io.PrintWriter;
 import java.io.StringWriter;
+import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -45,7 +48,9 @@ import org.apache.camel.Exchange;
 import org.apache.camel.StartupListener;
 import org.apache.camel.StaticService;
 import org.apache.camel.api.management.ManagedAttribute;
+import org.apache.camel.api.management.ManagedCamelContext;
 import org.apache.camel.api.management.ManagedResource;
+import org.apache.camel.api.management.mbean.ManagedCamelContextMBean;
 import org.apache.camel.component.platform.http.HttpEndpointModel;
 import org.apache.camel.component.platform.http.PlatformHttpComponent;
 import 
org.apache.camel.component.platform.http.plugin.JolokiaPlatformHttpPlugin;
@@ -59,6 +64,8 @@ import org.apache.camel.health.HealthCheck;
 import org.apache.camel.health.HealthCheckHelper;
 import org.apache.camel.health.HealthCheckRegistry;
 import org.apache.camel.spi.CamelEvent;
+import org.apache.camel.spi.ReloadStrategy;
+import org.apache.camel.support.CamelContextHelper;
 import org.apache.camel.support.ResolverHelper;
 import org.apache.camel.support.SimpleEventNotifierSupport;
 import org.apache.camel.support.jsse.SSLContextParameters;
@@ -69,6 +76,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.TimeUtils;
 import org.apache.camel.util.json.JsonObject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -87,6 +95,7 @@ public class MainHttpServer extends ServiceSupport implements 
CamelContextAware,
     private JolokiaPlatformHttpPlugin jolokiaPlugin;
 
     private VertxPlatformHttpServerConfiguration configuration = new 
VertxPlatformHttpServerConfiguration();
+    private boolean infoEnabled;
     private boolean devConsoleEnabled;
     private boolean healthCheckEnabled;
     private boolean jolokiaEnabled;
@@ -112,6 +121,15 @@ public class MainHttpServer extends ServiceSupport 
implements CamelContextAware,
         this.configuration = configuration;
     }
 
+    @ManagedAttribute(description = "Whether info is enabled (/q/info)")
+    public boolean isInfoEnabled() {
+        return infoEnabled;
+    }
+
+    public void setInfoEnabled(boolean infoEnabled) {
+        this.infoEnabled = infoEnabled;
+    }
+
     @ManagedAttribute(description = "Whether dev console is enabled (/q/dev)")
     public boolean isDevConsoleEnabled() {
         return devConsoleEnabled;
@@ -295,6 +313,9 @@ public class MainHttpServer extends ServiceSupport 
implements CamelContextAware,
     }
 
     protected void setupConsoles() {
+        if (infoEnabled) {
+            setupInfo();
+        }
         if (devConsoleEnabled) {
             setupDevConsole();
         }
@@ -393,6 +414,114 @@ public class MainHttpServer extends ServiceSupport 
implements CamelContextAware,
         });
     }
 
+    protected void setupInfo() {
+        final Route info = router.route("/q/info");
+        info.method(HttpMethod.GET);
+        info.produces("application/json");
+
+        Handler<RoutingContext> handler = new Handler<RoutingContext>() {
+
+            private String extractState(int status) {
+                if (status <= 4) {
+                    return "Starting";
+                } else if (status == 5) {
+                    return "Running";
+                } else if (status == 6) {
+                    return "Suspending";
+                } else if (status == 7) {
+                    return "Suspended";
+                } else if (status == 8) {
+                    return "Terminating";
+                } else if (status == 9) {
+                    return "Terminated";
+                } else {
+                    return "Terminated";
+                }
+            }
+
+            @Override
+            public void handle(RoutingContext ctx) {
+                ctx.response().putHeader("content-type", "application/json");
+
+                JsonObject root = new JsonObject();
+                JsonObject jo = new JsonObject();
+                root.put("java", jo);
+
+                RuntimeMXBean rmb = ManagementFactory.getRuntimeMXBean();
+                if (rmb != null) {
+                    jo.put("pid", rmb.getPid());
+                    jo.put("vendor", rmb.getVmVendor());
+                    jo.put("name", rmb.getVmName());
+                    jo.put("version", String.format("%s", 
System.getProperty("java.version")));
+                    jo.put("user", System.getProperty("user.name"));
+                    jo.put("dir", System.getProperty("user.dir"));
+                }
+
+                jo = new JsonObject();
+                root.put("camel", jo);
+
+                jo.put("name", camelContext.getName());
+                jo.put("version", camelContext.getVersion());
+                Collection<HealthCheck.Result> results = 
HealthCheckHelper.invoke(getCamelContext());
+                boolean up = results.stream().allMatch(h -> 
HealthCheck.State.UP.equals(h.getState()));
+                jo.put("ready", up ? "1/1" : "0/1");
+                jo.put("status", 
extractState(getCamelContext().getCamelContextExtension().getStatusPhase()));
+                int reloaded = 0;
+                Set<ReloadStrategy> rs = 
getCamelContext().hasServices(ReloadStrategy.class);
+                for (ReloadStrategy r : rs) {
+                    reloaded += r.getReloadCounter();
+                }
+                jo.put("reload", reloaded);
+                jo.put("age", CamelContextHelper.getUptime(camelContext));
+
+                ManagedCamelContext mcc
+                        = 
getCamelContext().getCamelContextExtension().getContextPlugin(ManagedCamelContext.class);
+                if (mcc != null) {
+                    ManagedCamelContextMBean mb = mcc.getManagedCamelContext();
+
+                    long total = camelContext.getRoutes().stream()
+                            .filter(r -> !r.isCreatedByRestDsl() && 
!r.isCreatedByKamelet()).count();
+                    long started = camelContext.getRoutes().stream()
+                            .filter(r -> !r.isCreatedByRestDsl() && 
!r.isCreatedByKamelet())
+                            .filter(ServiceHelper::isStarted).count();
+                    jo.put("routes", started + "/" + total);
+                    String thp = mb.getThroughput();
+                    thp = thp.replace(',', '.');
+                    if (!thp.isEmpty()) {
+                        jo.put("exchangesThroughput", thp + "/s");
+                    }
+                    jo.put("exchangesTotal", mb.getExchangesTotal());
+                    jo.put("exchangesFailed", mb.getExchangesFailed());
+                    jo.put("exchangesInflight", mb.getExchangesInflight());
+                    if (mb.getExchangesTotal() > 0) {
+                        jo.put("lastProcessingTime", 
mb.getLastProcessingTime());
+                        jo.put("deltaProcessingTime", 
mb.getDeltaProcessingTime());
+                    }
+                    Date last = mb.getLastExchangeCreatedTimestamp();
+                    if (last != null) {
+                        jo.put("sinceLastExchangeCreated", 
TimeUtils.printSince(last.getTime()));
+                    }
+                    last = mb.getLastExchangeFailureTimestamp();
+                    if (last != null) {
+                        jo.put("sinceLastExchangeFailed", 
TimeUtils.printSince(last.getTime()));
+                    }
+                    last = mb.getLastExchangeCompletedTimestamp();
+                    if (last != null) {
+                        jo.put("sinceLastExchangeCompleted", 
TimeUtils.printSince(last.getTime()));
+                    }
+                }
+
+                ctx.end(root.toJson());
+            }
+        };
+
+        // use blocking handler as the task can take longer time to complete
+        info.handler(new BlockingHandlerDecorator(handler, true));
+
+        platformHttpComponent.addHttpEndpoint("/q/info", null, null,
+                "application/json", null);
+    }
+
     protected void setupHealthCheckConsole() {
         final Route health = router.route("/q/health");
         health.method(HttpMethod.GET);
diff --git 
a/core/camel-main/src/generated/java/org/apache/camel/main/HttpServerConfigurationPropertiesConfigurer.java
 
b/core/camel-main/src/generated/java/org/apache/camel/main/HttpServerConfigurationPropertiesConfigurer.java
index badbe6fed5c..278d864875d 100644
--- 
a/core/camel-main/src/generated/java/org/apache/camel/main/HttpServerConfigurationPropertiesConfigurer.java
+++ 
b/core/camel-main/src/generated/java/org/apache/camel/main/HttpServerConfigurationPropertiesConfigurer.java
@@ -29,6 +29,8 @@ public class HttpServerConfigurationPropertiesConfigurer 
extends org.apache.came
         case "HealthCheckEnabled": 
target.setHealthCheckEnabled(property(camelContext, boolean.class, value)); 
return true;
         case "host":
         case "Host": target.setHost(property(camelContext, 
java.lang.String.class, value)); return true;
+        case "infoenabled":
+        case "InfoEnabled": target.setInfoEnabled(property(camelContext, 
boolean.class, value)); return true;
         case "jolokiaenabled":
         case "JolokiaEnabled": target.setJolokiaEnabled(property(camelContext, 
boolean.class, value)); return true;
         case "maxbodysize":
@@ -60,6 +62,8 @@ public class HttpServerConfigurationPropertiesConfigurer 
extends org.apache.came
         case "HealthCheckEnabled": return boolean.class;
         case "host":
         case "Host": return java.lang.String.class;
+        case "infoenabled":
+        case "InfoEnabled": return boolean.class;
         case "jolokiaenabled":
         case "JolokiaEnabled": return boolean.class;
         case "maxbodysize":
@@ -92,6 +96,8 @@ public class HttpServerConfigurationPropertiesConfigurer 
extends org.apache.came
         case "HealthCheckEnabled": return target.isHealthCheckEnabled();
         case "host":
         case "Host": return target.getHost();
+        case "infoenabled":
+        case "InfoEnabled": return target.isInfoEnabled();
         case "jolokiaenabled":
         case "JolokiaEnabled": return target.isJolokiaEnabled();
         case "maxbodysize":
diff --git 
a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
 
b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
index f2f63e72a4a..387d0a54077 100644
--- 
a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
+++ 
b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
@@ -253,6 +253,7 @@
     { "name": "camel.server.enabled", "description": "Whether embedded HTTP 
server is enabled. By default, the server is not enabled.", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "boolean", 
"javaType": "boolean", "defaultValue": "false" },
     { "name": "camel.server.healthCheckEnabled", "description": "Whether to 
enable health-check console. If enabled then you can access health-check status 
on context-path: \/q\/health", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "boolean", 
"javaType": "boolean", "defaultValue": "false" },
     { "name": "camel.server.host", "description": "Hostname to use for binding 
embedded HTTP server", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string", 
"javaType": "java.lang.String", "defaultValue": "0.0.0.0" },
+    { "name": "camel.server.infoEnabled", "description": "Whether to enable 
info console. If enabled then you can see some basic Camel information at 
\/q\/info", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "boolean", 
"javaType": "boolean", "defaultValue": "false" },
     { "name": "camel.server.jolokiaEnabled", "description": "Whether to enable 
jolokia. If enabled then you can access jolokia api on context-path: 
\/q\/jolokia", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "boolean", 
"javaType": "boolean", "defaultValue": "false" },
     { "name": "camel.server.maxBodySize", "description": "Maximum HTTP body 
size the embedded HTTP server can accept.", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "integer", 
"javaType": "java.lang.Long" },
     { "name": "camel.server.metricsEnabled", "description": "Whether to enable 
metrics. If enabled then you can access metrics on context-path: \/q\/metrics", 
"sourceType": "org.apache.camel.main.HttpServerConfigurationProperties", 
"type": "boolean", "javaType": "boolean", "defaultValue": "false" },
diff --git a/core/camel-main/src/main/docs/main.adoc 
b/core/camel-main/src/main/docs/main.adoc
index f95c98836b2..a6326e2fdb7 100644
--- a/core/camel-main/src/main/docs/main.adoc
+++ b/core/camel-main/src/main/docs/main.adoc
@@ -168,7 +168,7 @@ The camel.routecontroller supports 12 options, which are 
listed below.
 
 
 === Camel Embedded HTTP Server (only for standalone; not Spring Boot or 
Quarkus) configurations
-The camel.server supports 12 options, which are listed below.
+The camel.server supports 13 options, which are listed below.
 
 [width="100%",cols="2,5,^1,2",options="header"]
 |===
@@ -177,6 +177,7 @@ The camel.server supports 12 options, which are listed 
below.
 | *camel.server.enabled* | Whether embedded HTTP server is enabled. By 
default, the server is not enabled. | false | boolean
 | *camel.server.healthCheck{zwsp}Enabled* | Whether to enable health-check 
console. If enabled then you can access health-check status on context-path: 
/q/health | false | boolean
 | *camel.server.host* | Hostname to use for binding embedded HTTP server | 
0.0.0.0 | String
+| *camel.server.infoEnabled* | Whether to enable info console. If enabled then 
you can see some basic Camel information at /q/info | false | boolean
 | *camel.server.jolokiaEnabled* | Whether to enable jolokia. If enabled then 
you can access jolokia api on context-path: /q/jolokia | false | boolean
 | *camel.server.maxBodySize* | Maximum HTTP body size the embedded HTTP server 
can accept. |  | Long
 | *camel.server.metricsEnabled* | Whether to enable metrics. If enabled then 
you can access metrics on context-path: /q/metrics | false | boolean
diff --git 
a/core/camel-main/src/main/java/org/apache/camel/main/HttpServerConfigurationProperties.java
 
b/core/camel-main/src/main/java/org/apache/camel/main/HttpServerConfigurationProperties.java
index 93fff2e5e26..c9f2d63cc2c 100644
--- 
a/core/camel-main/src/main/java/org/apache/camel/main/HttpServerConfigurationProperties.java
+++ 
b/core/camel-main/src/main/java/org/apache/camel/main/HttpServerConfigurationProperties.java
@@ -39,6 +39,7 @@ public class HttpServerConfigurationProperties implements 
BootstrapCloseable {
     private Long maxBodySize;
     private boolean useGlobalSslContextParameters;
 
+    private boolean infoEnabled;
     private boolean devConsoleEnabled;
     private boolean healthCheckEnabled;
     private boolean jolokiaEnabled;
@@ -125,6 +126,17 @@ public class HttpServerConfigurationProperties implements 
BootstrapCloseable {
         this.useGlobalSslContextParameters = useGlobalSslContextParameters;
     }
 
+    public boolean isInfoEnabled() {
+        return infoEnabled;
+    }
+
+    /**
+     * Whether to enable info console. If enabled then you can see some basic 
Camel information at /q/info
+     */
+    public void setInfoEnabled(boolean infoEnabled) {
+        this.infoEnabled = infoEnabled;
+    }
+
     public boolean isDevConsoleEnabled() {
         return devConsoleEnabled;
     }
@@ -246,6 +258,14 @@ public class HttpServerConfigurationProperties implements 
BootstrapCloseable {
         return this;
     }
 
+    /**
+     * Whether to enable info console. If enabled then you can see some basic 
Camel information at /q/info
+     */
+    public HttpServerConfigurationProperties withInfoEnabled(boolean 
infoEnabled) {
+        this.infoEnabled = infoEnabled;
+        return this;
+    }
+
     /**
      * Whether to enable developer console (not intended for production use). 
Dev console must also be enabled on
      * CamelContext. For example by setting camel.context.dev-console=true in 
application.properties, or via code
diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
index ae3e4ae6f8a..68218bc20bb 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
@@ -3403,6 +3403,9 @@ The follow options related to _exporting_, can be 
configured in `application.pro
 |`camel.jbang.console`
 | Developer console at /q/dev on local HTTP server (port 8080 by default) when 
running standalone Camel
 
+|`camel.jbang.info`
+| Info console at /q/info on local HTTP server (port 8080 by default) when 
running standalone Camel
+
 |`camel.jbang.health`
 | Health check at /q/health on local HTTP server (port 8080 by default) when 
running standalone Camel
 
diff --git 
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java 
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java
index e25118d6e36..8035e6cabd8 100644
--- 
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java
+++ 
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java
@@ -452,6 +452,7 @@ public class KameletMain extends MainCommandLineSupport {
         boolean console = 
"true".equals(getInitialProperties().get("camel.jbang.console"));
         if (console) {
             configure().httpServer().withEnabled(true);
+            configure().httpServer().withInfoEnabled(true); // also enable 
info if console is enabled
             configure().httpServer().withDevConsoleEnabled(true);
         }
 
@@ -474,6 +475,11 @@ public class KameletMain extends MainCommandLineSupport {
         if (tracing) {
             configure().withBacklogTracing(true);
         }
+        boolean infoConsole = 
"true".equals(getInitialProperties().get("camel.jbang.info"));
+        if (infoConsole) {
+            configure().httpServer().withEnabled(true);
+            configure().httpServer().withInfoEnabled(true);
+        }
         boolean health = 
"true".equals(getInitialProperties().get("camel.jbang.health"));
         if (health) {
             configure().health().withEnabled(true);

Reply via email to