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);