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 95397a15f04 Debug jmx (#14129)
95397a15f04 is described below
commit 95397a15f0433886d04941273c2643b6de977722
Author: Claus Ibsen <[email protected]>
AuthorDate: Tue May 14 11:14:14 2024 +0200
Debug jmx (#14129)
* CAMEL-20760: camel-core - Allow to turn on|off RMI connector for tooling
based debuggers
---
.../main/camel-main-configuration-metadata.json | 2 +
.../component/debug/CamelDebuggerFactory.java | 9 +++--
.../impl/debugger/DebuggerJmxConnectorService.java | 37 ++++++++++--------
.../DebuggerConfigurationPropertiesConfigurer.java | 12 ++++++
.../camel-main-configuration-metadata.json | 2 +
core/camel-main/src/main/docs/main.adoc | 4 +-
.../org/apache/camel/main/BaseMainSupport.java | 11 +++++-
.../main/DebuggerConfigurationProperties.java | 44 ++++++++++++++++++++++
8 files changed, 100 insertions(+), 21 deletions(-)
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 6a5e64eabbf..3ed4a3937f0 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
@@ -145,6 +145,8 @@
{ "name": "camel.debug.includeException", "description": "Trace messages
to include exception if the message failed", "sourceType":
"org.apache.camel.main.DebuggerConfigurationProperties", "type": "boolean",
"javaType": "boolean", "defaultValue": true },
{ "name": "camel.debug.includeExchangeProperties", "description": "Whether
to include the exchange properties in the traced message", "sourceType":
"org.apache.camel.main.DebuggerConfigurationProperties", "type": "boolean",
"javaType": "boolean", "defaultValue": true },
{ "name": "camel.debug.includeExchangeVariables", "description": "Whether
to include the exchange variables in the traced message", "sourceType":
"org.apache.camel.main.DebuggerConfigurationProperties", "type": "boolean",
"javaType": "boolean", "defaultValue": true },
+ { "name": "camel.debug.jmxConnectorEnabled", "description": "Whether to
create JMX connector that allows tooling to control the Camel debugger. This is
what the IDEA and VSCode tooling is using.", "sourceType":
"org.apache.camel.main.DebuggerConfigurationProperties", "type": "boolean",
"javaType": "boolean", "defaultValue": true },
+ { "name": "camel.debug.jmxConnectorPort", "description": "Port number to
expose a JMX RMI connector for tooling that needs to control the debugger.",
"sourceType": "org.apache.camel.main.DebuggerConfigurationProperties", "type":
"integer", "javaType": "int", "defaultValue": 1099 },
{ "name": "camel.debug.loggingLevel", "description": "The debugger logging
level to use when logging activity.", "sourceType":
"org.apache.camel.main.DebuggerConfigurationProperties", "type": "object",
"javaType": "org.apache.camel.LoggingLevel", "defaultValue": "INFO", "enum": [
"ERROR", "WARN", "INFO", "DEBUG", "TRACE", "OFF" ] },
{ "name": "camel.debug.singleStepIncludeStartEnd", "description": "In
single step mode, then when the exchange is created and completed, then
simulate a breakpoint at start and end, that allows to suspend and watch the
incoming\/complete exchange at the route (you can see message body as response,
failed exception etc).", "sourceType":
"org.apache.camel.main.DebuggerConfigurationProperties", "type": "boolean",
"javaType": "boolean", "defaultValue": "false" },
{ "name": "camel.debug.standby", "description": "To set the debugger in
standby mode, where the debugger will be installed by not automatic enabled.
The debugger can then later be enabled explicit from Java, JMX or tooling.",
"sourceType": "org.apache.camel.main.DebuggerConfigurationProperties", "type":
"boolean", "javaType": "boolean", "defaultValue": "false" },
diff --git
a/components/camel-debug/src/main/java/org/apache/camel/component/debug/CamelDebuggerFactory.java
b/components/camel-debug/src/main/java/org/apache/camel/component/debug/CamelDebuggerFactory.java
index aaf032cc051..fb85af6fb1b 100644
---
a/components/camel-debug/src/main/java/org/apache/camel/component/debug/CamelDebuggerFactory.java
+++
b/components/camel-debug/src/main/java/org/apache/camel/component/debug/CamelDebuggerFactory.java
@@ -17,6 +17,7 @@
package org.apache.camel.component.debug;
import org.apache.camel.CamelContext;
+import org.apache.camel.impl.debugger.DebuggerJmxConnectorService;
import org.apache.camel.impl.debugger.DefaultBacklogDebugger;
import org.apache.camel.spi.BacklogDebugger;
import org.apache.camel.spi.Debugger;
@@ -43,6 +44,11 @@ public class CamelDebuggerFactory implements DebuggerFactory
{
// enable debugger on camel
camelContext.setDebugging(true);
+ // to make debugging possible for tooling we need to make it
possible to do remote JMX connection
+ DebuggerJmxConnectorService connector = new
DebuggerJmxConnectorService();
+ connector.setCreateConnector(true);
+ camelContext.addService(connector);
+
// we need to enable debugger after context is started
camelContext.addLifecycleStrategy(new LifecycleStrategySupport() {
@Override
@@ -61,9 +67,6 @@ public class CamelDebuggerFactory implements DebuggerFactory {
camelContext.addService(backlog, true, true);
}
- // to make debugging possible for tooling we need to make it possible
to do remote JMX connection
- camelContext.addService(new JmxConnectorService());
-
// return null as we fool camel-core into using this backlog debugger
as we added it as a service
return null;
}
diff --git
a/components/camel-debug/src/main/java/org/apache/camel/component/debug/JmxConnectorService.java
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/debugger/DebuggerJmxConnectorService.java
similarity index 77%
rename from
components/camel-debug/src/main/java/org/apache/camel/component/debug/JmxConnectorService.java
rename to
core/camel-base-engine/src/main/java/org/apache/camel/impl/debugger/DebuggerJmxConnectorService.java
index d0c75f85561..95411d9640c 100644
---
a/components/camel-debug/src/main/java/org/apache/camel/component/debug/JmxConnectorService.java
+++
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/debugger/DebuggerJmxConnectorService.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.camel.component.debug;
+package org.apache.camel.impl.debugger;
import java.io.IOException;
import java.lang.management.ManagementFactory;
@@ -36,22 +36,23 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- * To make it possible to do JMX debugging via JMX remote
+ * To make it possible to do Camel debugging via JMX remote
*/
-public class JmxConnectorService extends ServiceSupport implements
CamelContextAware {
+public class DebuggerJmxConnectorService extends ServiceSupport implements
CamelContextAware {
public static final String DEFAULT_HOST = "localhost";
public static final int DEFAULT_REGISTRY_PORT = 1099;
public static final int DEFAULT_CONNECTION_PORT = -1;
public static final String DEFAULT_SERVICE_URL_PATH = "/jmxrmi/camel";
- private static final Logger LOG =
LoggerFactory.getLogger(JmxConnectorService.class);
+ private static final Logger LOG =
LoggerFactory.getLogger(DebuggerJmxConnectorService.class);
private CamelContext camelContext;
private MBeanServer server;
private JMXConnectorServer cs;
private Registry registry;
+ private int registryPort = DEFAULT_REGISTRY_PORT;
private boolean createConnector = true;
@Override
@@ -72,11 +73,15 @@ public class JmxConnectorService extends ServiceSupport
implements CamelContextA
this.createConnector = createConnector;
}
+ public void setRegistryPort(int registryPort) {
+ this.registryPort = registryPort;
+ }
+
@Override
protected void doStart() throws Exception {
server = ManagementFactory.getPlatformMBeanServer();
- if (createConnector) {
+ if (createConnector && registryPort > 0) {
createJmxConnector(DEFAULT_HOST);
}
}
@@ -87,9 +92,9 @@ public class JmxConnectorService extends ServiceSupport
implements CamelContextA
if (cs != null) {
try {
cs.stop();
- LOG.debug("Stopped JMX Connector");
+ LOG.debug("Stopped Debugger JMX Connector");
} catch (IOException e) {
- LOG.debug("Error occurred during stopping JMXConnectorService:
{}. This exception will be ignored.", cs);
+ LOG.debug("Error occurred during stopping CamelDebugger JMX
Connector: " + cs + ". This exception will be ignored.", e);
}
cs = null;
}
@@ -100,13 +105,12 @@ public class JmxConnectorService extends ServiceSupport
implements CamelContextA
UnicastRemoteObject.unexportObject(registry, true);
LOG.debug("Unexported JMX RMI Registry");
} catch (NoSuchObjectException e) {
- LOG.debug("Error occurred while unexporting JMX RMI registry.
This exception will be ignored.");
+ LOG.debug("Error occurred while unexporting JMX RMI registry.
This exception will be ignored.", e);
}
}
}
protected void createJmxConnector(String host) throws IOException {
- int registryPort = DEFAULT_REGISTRY_PORT;
String serviceUrlPath = DEFAULT_SERVICE_URL_PATH;
int connectorPort = DEFAULT_CONNECTION_PORT;
@@ -114,7 +118,7 @@ public class JmxConnectorService extends ServiceSupport
implements CamelContextA
registry = LocateRegistry.createRegistry(registryPort);
LOG.debug("Created JMXConnector RMI registry on port {}",
registryPort);
} catch (RemoteException ex) {
- // The registry may had been created, we could get the registry
instead
+ // The registry may have been created, we could get the registry
instead
}
// must start with leading slash
@@ -122,9 +126,10 @@ public class JmxConnectorService extends ServiceSupport
implements CamelContextA
// Create an RMI connector and start it
final JMXServiceURL url;
if (connectorPort > 0) {
+ // we do not allow remote RMI access so this code is disabled
url = new JMXServiceURL(
"service:jmx:rmi://" + host + ":" + connectorPort +
"/jndi/rmi://" + host
- + ":" + registryPort + path);
+ + ":" + registryPort + path);
} else {
url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + host +
":" + registryPort + path);
}
@@ -133,13 +138,13 @@ public class JmxConnectorService extends ServiceSupport
implements CamelContextA
// use async thread for starting the JMX Connector
// (no need to use a thread pool or enlist in JMX as this thread is
terminated when the JMX connector has been started)
- Thread thread =
getCamelContext().getExecutorServiceManager().newThread("CamelJMXConnector", ()
-> {
+ Thread thread =
getCamelContext().getExecutorServiceManager().newThread("DebuggerJMXConnector",
() -> {
try {
- LOG.debug("Staring JMX Connector thread to listen at: {}",
url);
+ LOG.debug("Staring Debugger JMX Connector thread to listen at:
{}", url);
cs.start();
- LOG.info("JMX Connector thread started and listening at: {}",
url);
- } catch (IOException ioe) {
- LOG.warn("Could not start JMXConnector thread at: {}. JMX
Connector not in use.", url, ioe);
+ LOG.info("Debugger JMXConnector listening at: {}", url);
+ } catch (IOException e) {
+ LOG.warn("Cannot start Debugger JMX Connector thread at: {}.
JMX Connector not in use.", url, e);
}
});
thread.start();
diff --git
a/core/camel-main/src/generated/java/org/apache/camel/main/DebuggerConfigurationPropertiesConfigurer.java
b/core/camel-main/src/generated/java/org/apache/camel/main/DebuggerConfigurationPropertiesConfigurer.java
index ff3d8dc567f..820b997b6c0 100644
---
a/core/camel-main/src/generated/java/org/apache/camel/main/DebuggerConfigurationPropertiesConfigurer.java
+++
b/core/camel-main/src/generated/java/org/apache/camel/main/DebuggerConfigurationPropertiesConfigurer.java
@@ -39,6 +39,10 @@ public class DebuggerConfigurationPropertiesConfigurer
extends org.apache.camel.
case "includeExchangeProperties":
target.setIncludeExchangeProperties(property(camelContext, boolean.class,
value)); return true;
case "includeexchangevariables":
case "includeExchangeVariables":
target.setIncludeExchangeVariables(property(camelContext, boolean.class,
value)); return true;
+ case "jmxconnectorenabled":
+ case "jmxConnectorEnabled":
target.setJmxConnectorEnabled(property(camelContext, boolean.class, value));
return true;
+ case "jmxconnectorport":
+ case "jmxConnectorPort":
target.setJmxConnectorPort(property(camelContext, int.class, value)); return
true;
case "logginglevel":
case "loggingLevel": target.setLoggingLevel(property(camelContext,
org.apache.camel.LoggingLevel.class, value)); return true;
case "singlestepincludestartend":
@@ -69,6 +73,10 @@ public class DebuggerConfigurationPropertiesConfigurer
extends org.apache.camel.
case "includeExchangeProperties": return boolean.class;
case "includeexchangevariables":
case "includeExchangeVariables": return boolean.class;
+ case "jmxconnectorenabled":
+ case "jmxConnectorEnabled": return boolean.class;
+ case "jmxconnectorport":
+ case "jmxConnectorPort": return int.class;
case "logginglevel":
case "loggingLevel": return org.apache.camel.LoggingLevel.class;
case "singlestepincludestartend":
@@ -100,6 +108,10 @@ public class DebuggerConfigurationPropertiesConfigurer
extends org.apache.camel.
case "includeExchangeProperties": return
target.isIncludeExchangeProperties();
case "includeexchangevariables":
case "includeExchangeVariables": return
target.isIncludeExchangeVariables();
+ case "jmxconnectorenabled":
+ case "jmxConnectorEnabled": return target.isJmxConnectorEnabled();
+ case "jmxconnectorport":
+ case "jmxConnectorPort": return target.getJmxConnectorPort();
case "logginglevel":
case "loggingLevel": return target.getLoggingLevel();
case "singlestepincludestartend":
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 6a5e64eabbf..3ed4a3937f0 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
@@ -145,6 +145,8 @@
{ "name": "camel.debug.includeException", "description": "Trace messages
to include exception if the message failed", "sourceType":
"org.apache.camel.main.DebuggerConfigurationProperties", "type": "boolean",
"javaType": "boolean", "defaultValue": true },
{ "name": "camel.debug.includeExchangeProperties", "description": "Whether
to include the exchange properties in the traced message", "sourceType":
"org.apache.camel.main.DebuggerConfigurationProperties", "type": "boolean",
"javaType": "boolean", "defaultValue": true },
{ "name": "camel.debug.includeExchangeVariables", "description": "Whether
to include the exchange variables in the traced message", "sourceType":
"org.apache.camel.main.DebuggerConfigurationProperties", "type": "boolean",
"javaType": "boolean", "defaultValue": true },
+ { "name": "camel.debug.jmxConnectorEnabled", "description": "Whether to
create JMX connector that allows tooling to control the Camel debugger. This is
what the IDEA and VSCode tooling is using.", "sourceType":
"org.apache.camel.main.DebuggerConfigurationProperties", "type": "boolean",
"javaType": "boolean", "defaultValue": true },
+ { "name": "camel.debug.jmxConnectorPort", "description": "Port number to
expose a JMX RMI connector for tooling that needs to control the debugger.",
"sourceType": "org.apache.camel.main.DebuggerConfigurationProperties", "type":
"integer", "javaType": "int", "defaultValue": 1099 },
{ "name": "camel.debug.loggingLevel", "description": "The debugger logging
level to use when logging activity.", "sourceType":
"org.apache.camel.main.DebuggerConfigurationProperties", "type": "object",
"javaType": "org.apache.camel.LoggingLevel", "defaultValue": "INFO", "enum": [
"ERROR", "WARN", "INFO", "DEBUG", "TRACE", "OFF" ] },
{ "name": "camel.debug.singleStepIncludeStartEnd", "description": "In
single step mode, then when the exchange is created and completed, then
simulate a breakpoint at start and end, that allows to suspend and watch the
incoming\/complete exchange at the route (you can see message body as response,
failed exception etc).", "sourceType":
"org.apache.camel.main.DebuggerConfigurationProperties", "type": "boolean",
"javaType": "boolean", "defaultValue": "false" },
{ "name": "camel.debug.standby", "description": "To set the debugger in
standby mode, where the debugger will be installed by not automatic enabled.
The debugger can then later be enabled explicit from Java, JMX or tooling.",
"sourceType": "org.apache.camel.main.DebuggerConfigurationProperties", "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 9030646a5de..794dfb33e63 100644
--- a/core/camel-main/src/main/docs/main.adoc
+++ b/core/camel-main/src/main/docs/main.adoc
@@ -188,7 +188,7 @@ The camel.server supports 13 options, which are listed
below.
=== Camel Debugger configurations
-The camel.debug supports 13 options, which are listed below.
+The camel.debug supports 15 options, which are listed below.
[width="100%",cols="2,5,^1,2",options="header"]
|===
@@ -202,6 +202,8 @@ The camel.debug supports 13 options, which are listed below.
| *camel.debug.includeException* | Trace messages to include exception if the
message failed | true | boolean
| *camel.debug.includeExchange{zwsp}Properties* | Whether to include the
exchange properties in the traced message | true | boolean
| *camel.debug.includeExchange{zwsp}Variables* | Whether to include the
exchange variables in the traced message | true | boolean
+| *camel.debug.jmxConnector{zwsp}Enabled* | Whether to create JMX connector
that allows tooling to control the Camel debugger. This is what the IDEA and
VSCode tooling is using. | true | boolean
+| *camel.debug.jmxConnectorPort* | Port number to expose a JMX RMI connector
for tooling that needs to control the debugger. | 1099 | int
| *camel.debug.loggingLevel* | The debugger logging level to use when logging
activity. | INFO | LoggingLevel
| *camel.debug.singleStepInclude{zwsp}StartEnd* | In single step mode, then
when the exchange is created and completed, then simulate a breakpoint at start
and end, that allows to suspend and watch the incoming/complete exchange at the
route (you can see message body as response, failed exception etc). | false |
boolean
| *camel.debug.standby* | To set the debugger in standby mode, where the
debugger will be installed by not automatic enabled. The debugger can then
later be enabled explicit from Java, JMX or tooling. | false | boolean
diff --git
a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
index 52f5bb07217..fd3ffdd137d 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
@@ -51,6 +51,7 @@ import org.apache.camel.console.DevConsoleRegistry;
import org.apache.camel.health.HealthCheck;
import org.apache.camel.health.HealthCheckRegistry;
import org.apache.camel.health.HealthCheckRepository;
+import org.apache.camel.impl.debugger.DebuggerJmxConnectorService;
import org.apache.camel.impl.debugger.DefaultBacklogDebugger;
import org.apache.camel.impl.engine.DefaultCompileStrategy;
import org.apache.camel.impl.engine.DefaultRoutesLoader;
@@ -1650,9 +1651,17 @@ public abstract class BaseMainSupport extends
BaseService {
debugger.setIncludeExchangeVariables(config.isIncludeExchangeVariables());
debugger.setIncludeException(config.isIncludeException());
debugger.setLoggingLevel(config.getLoggingLevel().name());
- debugger.setSuspendMode(config.isWaitForAttach());
+ debugger.setSuspendMode(config.isWaitForAttach()); // this option is
named wait-for-attach
debugger.setFallbackTimeout(config.getFallbackTimeout());
+ // enable jmx connector if port is set
+ if (config.isJmxConnectorEnabled()) {
+ DebuggerJmxConnectorService connector = new
DebuggerJmxConnectorService();
+ connector.setCreateConnector(true);
+ connector.setRegistryPort(config.getJmxConnectorPort());
+ camelContext.addService(connector);
+ }
+
// start debugger after context is started
camelContext.addLifecycleStrategy(new LifecycleStrategySupport() {
@Override
diff --git
a/core/camel-main/src/main/java/org/apache/camel/main/DebuggerConfigurationProperties.java
b/core/camel-main/src/main/java/org/apache/camel/main/DebuggerConfigurationProperties.java
index 931ce75f930..711a650761d 100644
---
a/core/camel-main/src/main/java/org/apache/camel/main/DebuggerConfigurationProperties.java
+++
b/core/camel-main/src/main/java/org/apache/camel/main/DebuggerConfigurationProperties.java
@@ -55,6 +55,10 @@ public class DebuggerConfigurationProperties implements
BootstrapCloseable {
private boolean includeException = true;
@Metadata(label = "advanced", defaultValue = "300")
private long fallbackTimeout = 300;
+ @Metadata(label = "advanced", defaultValue = "true")
+ private boolean jmxConnectorEnabled = true;
+ @Metadata(label = "advanced", defaultValue = "1099")
+ private int jmxConnectorPort = 1099;
public DebuggerConfigurationProperties(MainConfigurationProperties parent)
{
this.parent = parent;
@@ -221,6 +225,29 @@ public class DebuggerConfigurationProperties implements
BootstrapCloseable {
this.fallbackTimeout = fallbackTimeout;
}
+ public boolean isJmxConnectorEnabled() {
+ return jmxConnectorEnabled;
+ }
+
+ /**
+ * Whether to create JMX connector that allows tooling to control the
Camel debugger.
+ * This is what the IDEA and VSCode tooling is using.
+ */
+ public void setJmxConnectorEnabled(boolean jmxConnectorEnabled) {
+ this.jmxConnectorEnabled = jmxConnectorEnabled;
+ }
+
+ public int getJmxConnectorPort() {
+ return jmxConnectorPort;
+ }
+
+ /**
+ * Port number to expose a JMX RMI connector for tooling that needs to
control the debugger.
+ */
+ public void setJmxConnectorPort(int jmxConnectorPort) {
+ this.jmxConnectorPort = jmxConnectorPort;
+ }
+
/**
* Enables Debugger in your Camel application.
*/
@@ -334,4 +361,21 @@ public class DebuggerConfigurationProperties implements
BootstrapCloseable {
return this;
}
+ /**
+ * Whether to create JMX connector that allows tooling to control the
Camel debugger.
+ * This is what the IDEA and VSCode tooling is using.
+ */
+ public DebuggerConfigurationProperties withJmxConnectorEnabled(boolean
jmxConnectorEnabled) {
+ this.jmxConnectorEnabled = jmxConnectorEnabled;
+ return this;
+ }
+
+ /**
+ * Port number to expose a JMX RMI connector for tooling that needs to
control the debugger.
+ */
+ public DebuggerConfigurationProperties withJmxConnectorPort(int
jmxConnectorPort) {
+ this.jmxConnectorPort = jmxConnectorPort;
+ return this;
+ }
+
}