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 e48475ad95a Standby (#12039)
e48475ad95a is described below

commit e48475ad95aae03ec39bc388809b72b69964b111
Author: Claus Ibsen <[email protected]>
AuthorDate: Fri Nov 17 14:53:37 2023 +0100

    Standby (#12039)
    
    * CAMEL-20067: camel-core - Add debuggingStandby option
    
    * CAMEL-20067: camel-core - Add debuggingStandby option
---
 .../main/camel-main-configuration-metadata.json    |   1 +
 .../component/debug/CamelDebuggerFactory.java      |   5 +-
 .../main/java/org/apache/camel/CamelContext.java   |  12 ++
 .../java/org/apache/camel/spi/BacklogDebugger.java |  16 +++
 .../impl/debugger/DefaultBacklogDebugger.java      |  15 ++-
 .../camel/impl/engine/AbstractCamelContext.java    |  13 ++-
 .../apache/camel/impl/engine/DefaultChannel.java   |   2 +-
 .../apache/camel/impl/console/DebugDevConsole.java |   8 +-
 .../apache/camel/impl/CamelContextConfigurer.java  |   6 +
 .../DebuggerConfigurationPropertiesConfigurer.java |   6 +
 .../camel-main-configuration-metadata.json         |   1 +
 core/camel-main/src/main/docs/main.adoc            |   3 +-
 .../org/apache/camel/main/BaseMainSupport.java     |  11 +-
 .../main/DebuggerConfigurationProperties.java      |  23 ++++
 .../camel/main/DefaultConfigurationConfigurer.java |   5 +
 .../mbean/ManagedBacklogDebuggerMBean.java         |   3 +
 .../management/mbean/ManagedBacklogDebugger.java   |   5 +
 .../management/BacklogDebuggerStandbyTest.java     | 126 +++++++++++++++++++++
 .../camel/management/BacklogDebuggerTest.java      |   3 +
 19 files changed, 255 insertions(+), 9 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 8e56959bc3c..b5d6c587081 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
@@ -153,6 +153,7 @@
     { "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.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" },
     { "name": "camel.debug.waitForAttach", "description": "Whether the 
debugger should suspend on startup, and wait for a remote debugger to attach. 
This is what the IDEA and VSCode tooling is using.", "sourceType": 
"org.apache.camel.main.DebuggerConfigurationProperties", "type": "boolean", 
"javaType": "boolean", "defaultValue": "false" },
     { "name": "camel.faulttolerance.bulkheadEnabled", "description": "Whether 
bulkhead is enabled or not on the circuit breaker. Default is false.", 
"sourceType": "org.apache.camel.main.FaultToleranceConfigurationProperties", 
"type": "boolean", "javaType": "java.lang.Boolean", "defaultValue": false },
     { "name": "camel.faulttolerance.bulkheadExecutorService", "description": 
"References to a custom thread pool to use when bulkhead is enabled.", 
"sourceType": "org.apache.camel.main.FaultToleranceConfigurationProperties", 
"type": "string", "javaType": "java.lang.String" },
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 6dd9e4bae11..f2842d56b60 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
@@ -37,7 +37,10 @@ public class CamelDebuggerFactory implements DebuggerFactory 
{
             camelContext.addLifecycleStrategy(new LifecycleStrategySupport() {
                 @Override
                 public void onContextStarted(CamelContext context) {
-                    backlog.enableDebugger();
+                    // only enable debugger if not in standby mode
+                    if (!backlog.isStandby()) {
+                        backlog.enableDebugger();
+                    }
                 }
 
                 @Override
diff --git a/core/camel-api/src/main/java/org/apache/camel/CamelContext.java 
b/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
index 041bb697acf..cbf1548e1dd 100644
--- a/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
+++ b/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
@@ -1180,6 +1180,18 @@ public interface CamelContext extends 
CamelContextLifecycle, RuntimeConfiguratio
      */
     boolean isBacklogTracingStandby();
 
+    /**
+     * Whether to set backlog debugger on standby. If on standby then the 
backlog debugger is installed and made
+     * available. Then the backlog debugger can be enabled later at runtime 
via JMX or via Java API.
+     */
+    void setDebugStandby(boolean debugStandby);
+
+    /**
+     * Whether to set backlog debugger on standby. If on standby then the 
backlog debugger is installed and made
+     * available. Then the backlog debugger can be enabled later at runtime 
via JMX or via Java API.
+     */
+    boolean isDebugStandby();
+
     /**
      * Whether backlog tracing should trace inner details from route templates 
(or kamelets). Turning this off can
      * reduce the verbosity of tracing when using many route templates, and 
allow to focus on tracing your own Camel
diff --git 
a/core/camel-api/src/main/java/org/apache/camel/spi/BacklogDebugger.java 
b/core/camel-api/src/main/java/org/apache/camel/spi/BacklogDebugger.java
index 284f33844fa..b8582c98f12 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/BacklogDebugger.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/BacklogDebugger.java
@@ -95,6 +95,22 @@ public interface BacklogDebugger extends StatefulService {
      */
     boolean isEnabled();
 
+    /**
+     * Whether the debugger is standby.
+     * <p>
+     * If a debugger is in standby then the tracer is activated during startup 
and are ready to be enabled manually via
+     * JMX or calling the enableDebugger method.
+     */
+    boolean isStandby();
+
+    /**
+     * Whether the debugger is standby.
+     * <p>
+     * If a debugger is in standby then the tracer is activated during startup 
and are ready to be enabled manually via
+     * JMX or calling the enableDebugger method.
+     */
+    void setStandby(boolean standby);
+
     /**
      * Does the node have a breakpoint
      */
diff --git 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/debugger/DefaultBacklogDebugger.java
 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/debugger/DefaultBacklogDebugger.java
index e37fccaecc5..8ccc3a2cc01 100644
--- 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/debugger/DefaultBacklogDebugger.java
+++ 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/debugger/DefaultBacklogDebugger.java
@@ -65,6 +65,7 @@ public final class DefaultBacklogDebugger extends 
ServiceSupport implements Back
     private LoggingLevel loggingLevel = LoggingLevel.INFO;
     private final CamelLogger logger = new CamelLogger(LOG, loggingLevel);
     private final AtomicBoolean enabled = new AtomicBoolean();
+    private final AtomicBoolean standby = new AtomicBoolean();
     private final AtomicLong debugCounter = new AtomicLong();
     private final Debugger debugger;
     private final ConcurrentMap<String, NodeBreakpoint> breakpoints = new 
ConcurrentHashMap<>();
@@ -138,7 +139,9 @@ public final class DefaultBacklogDebugger extends 
ServiceSupport implements Back
         // must enable message history for debugger to capture more details
         context.setMessageHistory(true);
 
-        return new DefaultBacklogDebugger(context, resolveSuspendMode());
+        DefaultBacklogDebugger answer = new DefaultBacklogDebugger(context, 
resolveSuspendMode());
+        answer.setStandby(context.isDebugStandby());
+        return answer;
     }
 
     /**
@@ -199,6 +202,16 @@ public final class DefaultBacklogDebugger extends 
ServiceSupport implements Back
         return enabled.get();
     }
 
+    @Override
+    public boolean isStandby() {
+        return standby.get();
+    }
+
+    @Override
+    public void setStandby(boolean standby) {
+        this.standby.set(standby);
+    }
+
     @Override
     public boolean hasBreakpoint(String nodeId) {
         return breakpoints.containsKey(nodeId);
diff --git 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
index 2d2726ea1d2..e4e0b4f63b6 100644
--- 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
+++ 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
@@ -237,6 +237,7 @@ public abstract class AbstractCamelContext extends 
BaseService
     private String tracingLoggingFormat;
     private Boolean modeline = Boolean.FALSE;
     private Boolean debug = Boolean.FALSE;
+    private Boolean debugStandby = Boolean.FALSE;
     private String debugBreakpoints;
     private Boolean messageHistory = Boolean.FALSE;
     private Boolean logMask = Boolean.FALSE;
@@ -1738,6 +1739,16 @@ public abstract class AbstractCamelContext extends 
BaseService
         return debug;
     }
 
+    @Override
+    public void setDebugStandby(boolean debugStandby) {
+        this.debugStandby = debugStandby;
+    }
+
+    @Override
+    public boolean isDebugStandby() {
+        return debugStandby != null && debugStandby;
+    }
+
     public void setDebuggingBreakpoints(String debugBreakpoints) {
         this.debugBreakpoints = debugBreakpoints;
     }
@@ -2254,7 +2265,7 @@ public abstract class AbstractCamelContext extends 
BaseService
                 }
             }
         }
-        if (!debuggerDetected && isDebugging()) {
+        if (!debuggerDetected && (isDebugging() || isDebugStandby())) {
             // debugging enabled but camel-debug was not auto-detected from 
classpath
             // so install default debugger
             BacklogDebugger backlog = 
DefaultBacklogDebugger.createDebugger(this);
diff --git 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultChannel.java
 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultChannel.java
index 84fb4e61f2a..07539ebedc0 100644
--- 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultChannel.java
+++ 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultChannel.java
@@ -174,7 +174,7 @@ public class DefaultChannel extends CamelInternalProcessor 
implements Channel {
 
         // then wrap the output with the tracer and debugger (debugger first,
         // as we do not want regular tracer to trace the debugger)
-        if (route.isDebugging()) {
+        if (camelContext.isDebugStandby() || route.isDebugging()) {
             final Debugger customDebugger = camelContext.getDebugger();
             if (customDebugger != null) {
                 // use custom debugger
diff --git 
a/core/camel-console/src/main/java/org/apache/camel/impl/console/DebugDevConsole.java
 
b/core/camel-console/src/main/java/org/apache/camel/impl/console/DebugDevConsole.java
index 6f6540ce673..72100c0295a 100644
--- 
a/core/camel-console/src/main/java/org/apache/camel/impl/console/DebugDevConsole.java
+++ 
b/core/camel-console/src/main/java/org/apache/camel/impl/console/DebugDevConsole.java
@@ -67,6 +67,7 @@ public class DebugDevConsole extends AbstractDevConsole {
         if (backlog != null) {
             sb.append("Settings:");
             sb.append(String.format("\n    Enabled: %s", backlog.isEnabled()));
+            sb.append(String.format("\n    Standby: %s", backlog.isStandby()));
             sb.append(String.format("\n    Suspended Mode: %s", 
backlog.isSuspendMode()));
             sb.append(String.format("\n    Fallback Timeout: %ss", 
backlog.getFallbackTimeout())); // is in seconds
             sb.append(String.format("\n    Logging Level: %s", 
backlog.getLoggingLevel()));
@@ -107,7 +108,11 @@ public class DebugDevConsole extends AbstractDevConsole {
             return;
         }
 
-        if ("attach".equalsIgnoreCase(command)) {
+        if ("enable".equalsIgnoreCase(command)) {
+            backlog.enableDebugger();
+        } else if ("disable".equalsIgnoreCase(command)) {
+            backlog.disableDebugger();
+        } else if ("attach".equalsIgnoreCase(command)) {
             backlog.attach();
         } else if ("detach".equalsIgnoreCase(command)) {
             backlog.detach();
@@ -147,6 +152,7 @@ public class DebugDevConsole extends AbstractDevConsole {
         BacklogDebugger backlog = 
getCamelContext().hasService(BacklogDebugger.class);
         if (backlog != null) {
             root.put("enabled", backlog.isEnabled());
+            root.put("standby", backlog.isStandby());
             root.put("suspendedMode", backlog.isSuspendMode());
             root.put("fallbackTimeout", backlog.getFallbackTimeout());
             root.put("loggingLevel", backlog.getLoggingLevel());
diff --git 
a/core/camel-core-engine/src/generated/java/org/apache/camel/impl/CamelContextConfigurer.java
 
b/core/camel-core-engine/src/generated/java/org/apache/camel/impl/CamelContextConfigurer.java
index 43067b7d8e7..36058f48b6b 100644
--- 
a/core/camel-core-engine/src/generated/java/org/apache/camel/impl/CamelContextConfigurer.java
+++ 
b/core/camel-core-engine/src/generated/java/org/apache/camel/impl/CamelContextConfigurer.java
@@ -39,6 +39,8 @@ public class CamelContextConfigurer extends 
org.apache.camel.support.component.P
         case "CaseInsensitiveHeaders": 
target.setCaseInsensitiveHeaders(property(camelContext, 
java.lang.Boolean.class, value)); return true;
         case "classresolver":
         case "ClassResolver": target.setClassResolver(property(camelContext, 
org.apache.camel.spi.ClassResolver.class, value)); return true;
+        case "debugstandby":
+        case "DebugStandby": target.setDebugStandby(property(camelContext, 
boolean.class, value)); return true;
         case "debugger":
         case "Debugger": target.setDebugger(property(camelContext, 
org.apache.camel.spi.Debugger.class, value)); return true;
         case "debugging":
@@ -158,6 +160,8 @@ public class CamelContextConfigurer extends 
org.apache.camel.support.component.P
         case "CaseInsensitiveHeaders": return java.lang.Boolean.class;
         case "classresolver":
         case "ClassResolver": return org.apache.camel.spi.ClassResolver.class;
+        case "debugstandby":
+        case "DebugStandby": return boolean.class;
         case "debugger":
         case "Debugger": return org.apache.camel.spi.Debugger.class;
         case "debugging":
@@ -278,6 +282,8 @@ public class CamelContextConfigurer extends 
org.apache.camel.support.component.P
         case "CaseInsensitiveHeaders": return 
target.isCaseInsensitiveHeaders();
         case "classresolver":
         case "ClassResolver": return target.getClassResolver();
+        case "debugstandby":
+        case "DebugStandby": return target.isDebugStandby();
         case "debugger":
         case "Debugger": return target.getDebugger();
         case "debugging":
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 811756e0a99..c9b2f6c3d92 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
@@ -41,6 +41,8 @@ public class DebuggerConfigurationPropertiesConfigurer 
extends org.apache.camel.
         case "LoggingLevel": target.setLoggingLevel(property(camelContext, 
org.apache.camel.LoggingLevel.class, value)); return true;
         case "singlestepincludestartend":
         case "SingleStepIncludeStartEnd": 
target.setSingleStepIncludeStartEnd(property(camelContext, boolean.class, 
value)); return true;
+        case "standby":
+        case "Standby": target.setStandby(property(camelContext, 
boolean.class, value)); return true;
         case "waitforattach":
         case "WaitForAttach": target.setWaitForAttach(property(camelContext, 
boolean.class, value)); return true;
         default: return false;
@@ -70,6 +72,8 @@ public class DebuggerConfigurationPropertiesConfigurer 
extends org.apache.camel.
         case "LoggingLevel": return org.apache.camel.LoggingLevel.class;
         case "singlestepincludestartend":
         case "SingleStepIncludeStartEnd": return boolean.class;
+        case "standby":
+        case "Standby": return boolean.class;
         case "waitforattach":
         case "WaitForAttach": return boolean.class;
         default: return null;
@@ -100,6 +104,8 @@ public class DebuggerConfigurationPropertiesConfigurer 
extends org.apache.camel.
         case "LoggingLevel": return target.getLoggingLevel();
         case "singlestepincludestartend":
         case "SingleStepIncludeStartEnd": return 
target.isSingleStepIncludeStartEnd();
+        case "standby":
+        case "Standby": return target.isStandby();
         case "waitforattach":
         case "WaitForAttach": return target.isWaitForAttach();
         default: return null;
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 8e56959bc3c..b5d6c587081 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
@@ -153,6 +153,7 @@
     { "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.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" },
     { "name": "camel.debug.waitForAttach", "description": "Whether the 
debugger should suspend on startup, and wait for a remote debugger to attach. 
This is what the IDEA and VSCode tooling is using.", "sourceType": 
"org.apache.camel.main.DebuggerConfigurationProperties", "type": "boolean", 
"javaType": "boolean", "defaultValue": "false" },
     { "name": "camel.faulttolerance.bulkheadEnabled", "description": "Whether 
bulkhead is enabled or not on the circuit breaker. Default is false.", 
"sourceType": "org.apache.camel.main.FaultToleranceConfigurationProperties", 
"type": "boolean", "javaType": "java.lang.Boolean", "defaultValue": false },
     { "name": "camel.faulttolerance.bulkheadExecutorService", "description": 
"References to a custom thread pool to use when bulkhead is enabled.", 
"sourceType": "org.apache.camel.main.FaultToleranceConfigurationProperties", 
"type": "string", "javaType": "java.lang.String" },
diff --git a/core/camel-main/src/main/docs/main.adoc 
b/core/camel-main/src/main/docs/main.adoc
index 6fc77d2bfd6..beac1024996 100644
--- a/core/camel-main/src/main/docs/main.adoc
+++ b/core/camel-main/src/main/docs/main.adoc
@@ -174,7 +174,7 @@ The camel.server supports 11 options, which are listed 
below.
 
 
 === Camel Debugger configurations
-The camel.debug supports 11 options, which are listed below.
+The camel.debug supports 12 options, which are listed below.
 
 [width="100%",cols="2,5,^1,2",options="header"]
 |===
@@ -189,6 +189,7 @@ The camel.debug supports 11 options, which are listed below.
 | *camel.debug.includeExchange{zwsp}Properties* | Whether to include the 
exchange properties in the traced message | true | boolean
 | *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
 | *camel.debug.waitForAttach* | Whether the debugger should suspend on 
startup, and wait for a remote debugger to attach. This is what the IDEA and 
VSCode tooling is using. | 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 660fa08e5f6..e04d05609b9 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
@@ -1561,7 +1561,7 @@ public abstract class BaseMainSupport extends BaseService 
{
         setPropertiesOnTarget(camelContext, config, properties, "camel.debug.",
                 failIfNotSet, true, autoConfiguredProperties);
 
-        if (!config.isEnabled()) {
+        if (!config.isEnabled() && !config.isStandby()) {
             return;
         }
 
@@ -1569,9 +1569,11 @@ public abstract class BaseMainSupport extends 
BaseService {
         camelContext.setSourceLocationEnabled(true);
 
         // enable debugger on camel
-        camelContext.setDebugging(true);
+        camelContext.setDebugging(config.isEnabled());
+        camelContext.setDebugStandby(config.isStandby());
 
         BacklogDebugger debugger = 
DefaultBacklogDebugger.createDebugger(camelContext);
+        debugger.setStandby(config.isStandby());
         debugger.setInitialBreakpoints(config.getBreakpoints());
         
debugger.setSingleStepIncludeStartEnd(config.isSingleStepIncludeStartEnd());
         debugger.setBodyMaxChars(config.getBodyMaxChars());
@@ -1587,7 +1589,10 @@ public abstract class BaseMainSupport extends 
BaseService {
         camelContext.addLifecycleStrategy(new LifecycleStrategySupport() {
             @Override
             public void onContextStarted(CamelContext context) {
-                debugger.enableDebugger();
+                // only enable debugger if not in standby mode
+                if (!debugger.isStandby()) {
+                    debugger.enableDebugger();
+                }
             }
 
             @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 de1113897e8..db62f28227b 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
@@ -31,6 +31,8 @@ public class DebuggerConfigurationProperties implements 
BootstrapCloseable {
 
     @Metadata
     private boolean enabled;
+    @Metadata
+    private boolean standby;
     @Metadata(label = "advanced")
     private boolean waitForAttach;
     @Metadata(defaultValue = "INFO")
@@ -76,6 +78,18 @@ public class DebuggerConfigurationProperties implements 
BootstrapCloseable {
         this.enabled = enabled;
     }
 
+    public boolean isStandby() {
+        return 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.
+     */
+    public void setStandby(boolean standby) {
+        this.standby = standby;
+    }
+
     public boolean isWaitForAttach() {
         return waitForAttach;
     }
@@ -202,6 +216,15 @@ public class DebuggerConfigurationProperties implements 
BootstrapCloseable {
         return (DebuggerConfigurationProperties) this;
     }
 
+    /**
+     * 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.
+     */
+    public DebuggerConfigurationProperties withStandby(boolean standby) {
+        this.standby = standby;
+        return (DebuggerConfigurationProperties) this;
+    }
+
     /**
      * Whether the debugger should suspend on startup, and wait for a remote 
debugger to attach. This is what the IDEA
      * and VSCode tooling is using.
diff --git 
a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java
 
b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java
index 3d958a06a0c..7b6f4bcedff 100644
--- 
a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java
+++ 
b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java
@@ -43,6 +43,7 @@ import org.apache.camel.model.Model;
 import org.apache.camel.model.ModelCamelContext;
 import org.apache.camel.model.ModelLifecycleStrategy;
 import org.apache.camel.spi.AsyncProcessorAwaitManager;
+import org.apache.camel.spi.BacklogDebugger;
 import org.apache.camel.spi.BeanIntrospection;
 import org.apache.camel.spi.ClassResolver;
 import org.apache.camel.spi.CliConnectorFactory;
@@ -395,6 +396,10 @@ public final class DefaultConfigurationConfigurer {
         if (bt != null) {
             
camelContext.getCamelContextExtension().addContextPlugin(BacklogTracer.class, 
bt);
         }
+        BacklogDebugger bd = getSingleBeanOfType(registry, 
BacklogDebugger.class);
+        if (bd != null) {
+            
camelContext.getCamelContextExtension().addContextPlugin(BacklogDebugger.class, 
bd);
+        }
         InflightRepository ir = getSingleBeanOfType(registry, 
InflightRepository.class);
         if (ir != null) {
             camelContext.setInflightRepository(ir);
diff --git 
a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedBacklogDebuggerMBean.java
 
b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedBacklogDebuggerMBean.java
index 1f77619f5d0..3a1dc32a26c 100644
--- 
a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedBacklogDebuggerMBean.java
+++ 
b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedBacklogDebuggerMBean.java
@@ -38,6 +38,9 @@ public interface ManagedBacklogDebuggerMBean {
     @ManagedAttribute(description = "Is debugger enabled")
     boolean isEnabled();
 
+    @ManagedAttribute(description = "Is debugger standby")
+    boolean isStandby();
+
     @ManagedOperation(description = "Enable the debugger")
     void enableDebugger();
 
diff --git 
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedBacklogDebugger.java
 
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedBacklogDebugger.java
index a3a86690544..a89d53da607 100644
--- 
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedBacklogDebugger.java
+++ 
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedBacklogDebugger.java
@@ -88,6 +88,11 @@ public class ManagedBacklogDebugger implements 
ManagedBacklogDebuggerMBean {
         return backlogDebugger.isEnabled();
     }
 
+    @Override
+    public boolean isStandby() {
+        return backlogDebugger.isStandby();
+    }
+
     @Override
     public void enableDebugger() {
         backlogDebugger.enableDebugger();
diff --git 
a/core/camel-management/src/test/java/org/apache/camel/management/BacklogDebuggerStandbyTest.java
 
b/core/camel-management/src/test/java/org/apache/camel/management/BacklogDebuggerStandbyTest.java
new file mode 100644
index 00000000000..a978657b658
--- /dev/null
+++ 
b/core/camel-management/src/test/java/org/apache/camel/management/BacklogDebuggerStandbyTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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.management;
+
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.impl.debugger.DefaultBacklogDebugger;
+import org.apache.camel.spi.BacklogDebugger;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledOnOs;
+import org.junit.jupiter.api.condition.OS;
+
+import static org.awaitility.Awaitility.await;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@DisabledOnOs(OS.AIX)
+public class BacklogDebuggerStandbyTest extends ManagementTestSupport {
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testBacklogDebuggerStandby() throws Exception {
+        MBeanServer mbeanServer = getMBeanServer();
+        ObjectName on = new ObjectName(
+                "org.apache.camel:context=" + context.getManagementName() + 
",type=tracer,name=BacklogDebugger");
+        assertNotNull(on);
+        mbeanServer.isRegistered(on);
+
+        Boolean enabled = (Boolean) mbeanServer.getAttribute(on, "Enabled");
+        assertEquals(Boolean.FALSE, enabled, "Should not be enabled");
+
+        Boolean standby = (Boolean) mbeanServer.getAttribute(on, "Standby");
+        assertEquals(Boolean.TRUE, standby, "Should be standby");
+
+        // enable debugger
+        mbeanServer.invoke(on, "enableDebugger", null, null);
+
+        enabled = (Boolean) mbeanServer.getAttribute(on, "Enabled");
+        assertEquals(Boolean.TRUE, enabled, "Should be enabled");
+
+        // add breakpoint at bar
+        mbeanServer.invoke(on, "addBreakpoint", new Object[] { "bar" }, new 
String[] { "java.lang.String" });
+
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedMessageCount(0);
+        mock.setSleepForEmptyTest(100);
+
+        template.sendBody("seda:start", "Hello World");
+
+        assertMockEndpointsSatisfied();
+
+        // wait for breakpoint at bar
+        await().atMost(1, TimeUnit.SECONDS).untilAsserted(() -> {
+            Set<String> suspended = (Set<String>) mbeanServer.invoke(on, 
"suspendedBreakpointNodeIds", null, null);
+            assertNotNull(suspended);
+            assertEquals(1, suspended.size());
+            assertEquals("bar", suspended.iterator().next());
+        });
+
+        // the message should be ours
+        String xml = (String) mbeanServer.invoke(on, 
"dumpTracedMessagesAsXml", new Object[] { "bar", false },
+                new String[] { "java.lang.String", "boolean" });
+        assertNotNull(xml);
+        log.info(xml);
+
+        assertTrue(xml.contains("Hello World"), "Should contain our body");
+        assertTrue(xml.contains("<toNode>bar</toNode>"), "Should contain bar 
node");
+
+        resetMocks();
+        mock.expectedMessageCount(1);
+
+        // resume breakpoint
+        mbeanServer.invoke(on, "resumeBreakpoint", new Object[] { "bar" }, new 
String[] { "java.lang.String" });
+
+        assertMockEndpointsSatisfied();
+
+        // and no suspended anymore
+        Set<String> nodes = (Set<String>) mbeanServer.invoke(on, 
"suspendedBreakpointNodeIds", null, null);
+        assertNotNull(nodes);
+        assertEquals(0, nodes.size());
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                // set debugger in standby mode
+                BacklogDebugger bd = 
DefaultBacklogDebugger.createDebugger(context);
+                bd.setStandby(true);
+                context.addService(bd);
+                context.setDebugging(true);
+
+                from("seda:start?concurrentConsumers=2")
+                        .setProperty("myProperty", 
constant("myValue")).id("setProp")
+                        .to("log:foo").id("foo")
+                        .to("log:bar").id("bar")
+                        .transform().constant("Bye World").id("transform")
+                        .to("log:cheese?showExchangeId=true").id("cheese")
+                        .to("mock:result").id("result");
+            }
+        };
+    }
+
+}
diff --git 
a/core/camel-management/src/test/java/org/apache/camel/management/BacklogDebuggerTest.java
 
b/core/camel-management/src/test/java/org/apache/camel/management/BacklogDebuggerTest.java
index cbd75bbc775..3d81881d01d 100644
--- 
a/core/camel-management/src/test/java/org/apache/camel/management/BacklogDebuggerTest.java
+++ 
b/core/camel-management/src/test/java/org/apache/camel/management/BacklogDebuggerTest.java
@@ -53,6 +53,9 @@ public class BacklogDebuggerTest extends 
ManagementTestSupport {
         Boolean enabled = (Boolean) mbeanServer.getAttribute(on, "Enabled");
         assertEquals(Boolean.FALSE, enabled, "Should not be enabled");
 
+        Boolean standby = (Boolean) mbeanServer.getAttribute(on, "Standby");
+        assertEquals(Boolean.FALSE, standby, "Should not be standby");
+
         // enable debugger
         mbeanServer.invoke(on, "enableDebugger", null, null);
 


Reply via email to