This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel.git
commit e9da9d0463be6d95d68409ab2049582c344652d6 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Wed Oct 13 13:24:57 2021 +0200 CAMEL-17072: Add standby mode for tracing. CAMEL-17074: camel-spring-main should only be for classic Spring XML files and it should not let camel-main do its additional auto configuration and route discovery, as all that is done with classic camel-spring-xml already. --- .../main/camel-main-configuration-metadata.json | 1 + .../src/main/docs/spring-main.adoc | 2 +- .../main/java/org/apache/camel/spring/Main.java | 2 + .../java/org/apache/camel/spring/MainIoCTest.java | 45 ----------------- .../java/org/apache/camel/spring/MainTest.java | 58 ---------------------- .../camel/impl/debugger/BacklogDebugger.java | 6 +-- .../camel/impl/engine/AbstractCamelContext.java | 11 ++-- .../camel/impl/engine/CamelInternalProcessor.java | 5 +- .../camel/impl/engine/SimpleCamelContext.java | 2 + .../issues/RetryWhileStackOverflowIssueTest.java | 2 - .../interceptor/DebugExceptionBreakpointTest.java | 3 +- .../DebugExceptionEventBreakpointTest.java | 3 +- .../interceptor/DebugSingleStepConditionTest.java | 3 +- .../processor/interceptor/DebugSingleStepTest.java | 3 +- .../camel/processor/interceptor/DebugTest.java | 3 +- .../org/apache/camel/main/BaseMainSupport.java | 27 +++++----- .../api/management/mbean/ManagedTracerMBean.java | 3 ++ .../camel/management/mbean/ManagedTracer.java | 5 ++ 18 files changed, 48 insertions(+), 136 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 6876b13..b41567a 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 @@ -100,6 +100,7 @@ { "name": "camel.main.threadNamePattern", "description": "Sets the thread name pattern used for creating the full thread name. The default pattern is: Camel (#camelId#) thread ##counter# - #name# Where #camelId# is the name of the CamelContext. and #counter# is a unique incrementing counter. and #name# is the regular thread name. You can also use #longName# which is the long thread name which can includes endpoint parameters etc.", "sourceType": "org.apache.camel.main.DefaultConfigur [...] { "name": "camel.main.tracing", "description": "Sets whether tracing is enabled or not. Default is false.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": "false" }, { "name": "camel.main.tracingPattern", "description": "Tracing pattern to match which node EIPs to trace. For example to match all To EIP nodes, use to. The pattern matches by node and route id's Multiple patterns can be separated by comma.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "string", "javaType": "java.lang.String" }, + { "name": "camel.main.tracingStandby", "description": "Whether to set tracing on standby. If on standby then the tracer is installed and made available. Then the tracer can be enabled later at runtime via JMX or via Tracer#setEnabled(boolean) .", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": "false" }, { "name": "camel.main.useBreadcrumb", "description": "Set whether breadcrumb is enabled. The default value is false.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": "false" }, { "name": "camel.main.useDataType", "description": "Whether to enable using data type on Camel messages. Data type are automatic turned on if one ore more routes has been explicit configured with input and output types. Otherwise data type is default off.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": "false" }, { "name": "camel.main.useMdcLogging", "description": "To turn on MDC logging", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": "false" }, diff --git a/components/camel-spring-main/src/main/docs/spring-main.adoc b/components/camel-spring-main/src/main/docs/spring-main.adoc index e92af73..57fa9ba 100644 --- a/components/camel-spring-main/src/main/docs/spring-main.adoc +++ b/components/camel-spring-main/src/main/docs/spring-main.adoc @@ -9,4 +9,4 @@ include::{cq-version}@camel-quarkus:ROOT:partial$reference/others/spring-main.ad *Since Camel {since}* -This module is used for running Spring standalone via a main class extended from `camel-main`. +This module is used for running classic Spring XML (not Spring Boot) via a main class extended from `camel-main`. diff --git a/components/camel-spring-main/src/main/java/org/apache/camel/spring/Main.java b/components/camel-spring-main/src/main/java/org/apache/camel/spring/Main.java index a6bcf2e..4780b1b 100644 --- a/components/camel-spring-main/src/main/java/org/apache/camel/spring/Main.java +++ b/components/camel-spring-main/src/main/java/org/apache/camel/spring/Main.java @@ -66,6 +66,8 @@ public class Main extends MainCommandLineSupport { private boolean allowMultipleCamelContexts; public Main() { + // do not run in standalone mode as we let Spring create and manage CamelContext but use this Main to bootstrap + standalone = false; } @Override diff --git a/components/camel-spring-main/src/test/java/org/apache/camel/spring/MainIoCTest.java b/components/camel-spring-main/src/test/java/org/apache/camel/spring/MainIoCTest.java deleted file mode 100644 index 3fb1348..0000000 --- a/components/camel-spring-main/src/test/java/org/apache/camel/spring/MainIoCTest.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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.spring; - -import org.apache.camel.CamelContext; -import org.apache.camel.component.mock.MockEndpoint; -import org.junit.jupiter.api.Test; - -public class MainIoCTest { - - @Test - public void testMain() throws Exception { - // lets make a simple route - Main main = new Main(); - // add as class so we get IoC from its packages - main.configure().addRoutesBuilder(MyMainIoCRouteBuilder.class); - main.start(); - - CamelContext camelContext = main.getCamelContext(); - - MockEndpoint endpoint = camelContext.getEndpoint("mock:results", MockEndpoint.class); - endpoint.expectedBodiesReceived("I am hello bean"); - - camelContext.createProducerTemplate().sendBody("direct:start", "Hello World"); - - endpoint.assertIsSatisfied(); - - main.stop(); - } - -} diff --git a/components/camel-spring-main/src/test/java/org/apache/camel/spring/MainTest.java b/components/camel-spring-main/src/test/java/org/apache/camel/spring/MainTest.java deleted file mode 100644 index d63866d..0000000 --- a/components/camel-spring-main/src/test/java/org/apache/camel/spring/MainTest.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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.spring; - -import java.util.List; - -import org.apache.camel.CamelContext; -import org.apache.camel.Exchange; -import org.apache.camel.builder.RouteBuilder; -import org.apache.camel.component.mock.MockEndpoint; -import org.junit.jupiter.api.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class MainTest { - private static final Logger LOG = LoggerFactory.getLogger(MainTest.class); - - @Test - public void testMain() throws Exception { - // lets make a simple route - Main main = new Main(); - main.configure().addRoutesBuilder(new RouteBuilder() { - @Override - public void configure() throws Exception { - from("file://src/test/data?initialDelay=0&delay=10&noop=true") - .process(new MyProcessor()) - .to("mock:results"); - } - }); - main.start(); - - CamelContext camelContext = main.getCamelContext(); - - MockEndpoint endpoint = camelContext.getEndpoint("mock:results", MockEndpoint.class); - // in case we add more files in src/test/data - endpoint.expectedMinimumMessageCount(2); - endpoint.assertIsSatisfied(); - List<Exchange> list = endpoint.getReceivedExchanges(); - - LOG.debug("Received: " + list); - - main.stop(); - } -} diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/debugger/BacklogDebugger.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/debugger/BacklogDebugger.java index 1ec0404..0951a5b 100644 --- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/debugger/BacklogDebugger.java +++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/debugger/BacklogDebugger.java @@ -51,12 +51,12 @@ import org.slf4j.LoggerFactory; * A {@link org.apache.camel.spi.Debugger} that has easy debugging functionality which can be used from JMX with * {@link org.apache.camel.api.management.mbean.ManagedBacklogDebuggerMBean}. * <p/> - * This implementation allows to set breakpoints (with or without a condition) and inspect the {@link Exchange} dumped + * This implementation allows setting breakpoints (with or without a condition) and inspect the {@link Exchange} dumped * in XML in {@link BacklogTracerEventMessage} format. There is operations to resume suspended breakpoints to continue - * routing the {@link Exchange}. There is also step functionality so you can single step a given {@link Exchange}. + * routing the {@link Exchange}. There is also step functionality, so you can single step a given {@link Exchange}. * <p/> * This implementation will only break the first {@link Exchange} that arrives to a breakpoint. If Camel routes using - * concurrency then sub-sequent {@link Exchange} will continue to be routed, if there breakpoint already holds a + * concurrency then sub-sequent {@link Exchange} will continue to be routed, if their breakpoint already holds a * suspended {@link Exchange}. */ public final class BacklogDebugger extends ServiceSupport { 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 5d9bdda..208f804 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 @@ -4437,16 +4437,16 @@ public abstract class AbstractCamelContext extends BaseService @Override public Debugger getDebugger() { return debugger; + // do not lazy create debugger as the DefaultDebugger is mostly only useable for testing + // and if debugging is enabled then Camel will use BacklogDebugger that can be remotely controlled via JMX management } @Override public void setDebugger(Debugger debugger) { if (isStartingOrStarted()) { - throw new IllegalStateException("Can not set debugger on a started CamelContext"); + throw new IllegalStateException("Cannot set debugger on a started CamelContext"); } this.debugger = doAddService(debugger, true, false, true); - // enable debugging if we set a custom debugger - setDebugging(true); } @Override @@ -4463,9 +4463,10 @@ public abstract class AbstractCamelContext extends BaseService @Override public void setTracer(Tracer tracer) { + if (isStartingOrStarted()) { + throw new IllegalStateException("Cannot set tracer on a started CamelContext"); + } this.tracer = doAddService(tracer, true, false, true); - // enable tracing if we set a custom tracer - setTracing(true); } @Override diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/CamelInternalProcessor.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/CamelInternalProcessor.java index 460e9b5..28bc972 100644 --- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/CamelInternalProcessor.java +++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/CamelInternalProcessor.java @@ -1002,7 +1002,6 @@ public class CamelInternalProcessor extends DelegateAsyncProcessor implements In private final NamedNode processorDefinition; private final NamedRoute routeDefinition; private final Synchronization tracingAfterRoute; - private boolean added; public TracingAdvice(Tracer tracer, NamedNode processorDefinition, NamedRoute routeDefinition, boolean first) { this.tracer = tracer; @@ -1015,16 +1014,14 @@ public class CamelInternalProcessor extends DelegateAsyncProcessor implements In @Override public Object before(Exchange exchange) throws Exception { if (tracer.isEnabled()) { - if (!added && tracingAfterRoute != null) { + if (tracingAfterRoute != null) { // add before route and after route tracing but only once per route, so check if there is already an existing boolean contains = exchange.getUnitOfWork().containsSynchronization(tracingAfterRoute); if (!contains) { - added = true; tracer.traceBeforeRoute(routeDefinition, exchange); exchange.adapt(ExtendedExchange.class).addOnCompletion(tracingAfterRoute); } } - tracer.traceBeforeNode(processorDefinition, exchange); } return null; diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/SimpleCamelContext.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/SimpleCamelContext.java index 711748f..11e0f67 100644 --- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/SimpleCamelContext.java +++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/SimpleCamelContext.java @@ -513,6 +513,8 @@ public class SimpleCamelContext extends AbstractCamelContext { } if (tracer == null) { tracer = new DefaultTracer(); + tracer.setEnabled(isTracing()); + tracer.setStandby(isTracingStandby()); setExtension(Tracer.class, tracer); } return tracer; diff --git a/core/camel-core/src/test/java/org/apache/camel/issues/RetryWhileStackOverflowIssueTest.java b/core/camel-core/src/test/java/org/apache/camel/issues/RetryWhileStackOverflowIssueTest.java index b2f6d59..68a8602 100644 --- a/core/camel-core/src/test/java/org/apache/camel/issues/RetryWhileStackOverflowIssueTest.java +++ b/core/camel-core/src/test/java/org/apache/camel/issues/RetryWhileStackOverflowIssueTest.java @@ -48,7 +48,6 @@ public class RetryWhileStackOverflowIssueTest extends ContextTestSupport { .handled(true).to("mock:error"); from("direct:start") - // .transacted() .throwException(new IllegalArgumentException("Forced")); } }; @@ -60,7 +59,6 @@ public class RetryWhileStackOverflowIssueTest extends ContextTestSupport { public String areWeCool() { int size = currentStackSize(); - System.out.println("Stacksize: " + size); if (counter++ < 1000) { return "no"; } else { diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/interceptor/DebugExceptionBreakpointTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/interceptor/DebugExceptionBreakpointTest.java index 5947a08..f8724ef 100644 --- a/core/camel-core/src/test/java/org/apache/camel/processor/interceptor/DebugExceptionBreakpointTest.java +++ b/core/camel-core/src/test/java/org/apache/camel/processor/interceptor/DebugExceptionBreakpointTest.java @@ -88,7 +88,8 @@ public class DebugExceptionBreakpointTest extends ContextTestSupport { return new RouteBuilder() { @Override public void configure() throws Exception { - // use debugger + // turn on debugging + context.setDebugging(true); context.setDebugger(new DefaultDebugger()); from("direct:start").to("log:foo").choice().when(body().contains("Camel")) diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/interceptor/DebugExceptionEventBreakpointTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/interceptor/DebugExceptionEventBreakpointTest.java index ac519c7..681eb8d 100644 --- a/core/camel-core/src/test/java/org/apache/camel/processor/interceptor/DebugExceptionEventBreakpointTest.java +++ b/core/camel-core/src/test/java/org/apache/camel/processor/interceptor/DebugExceptionEventBreakpointTest.java @@ -88,7 +88,8 @@ public class DebugExceptionEventBreakpointTest extends ContextTestSupport { return new RouteBuilder() { @Override public void configure() throws Exception { - // use debugger + // turn on debugging + context.setDebugging(true); context.setDebugger(new DefaultDebugger()); from("direct:start").to("log:foo").choice().when(body().contains("Camel")) diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/interceptor/DebugSingleStepConditionTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/interceptor/DebugSingleStepConditionTest.java index 986c9fe..8d7ee9a 100644 --- a/core/camel-core/src/test/java/org/apache/camel/processor/interceptor/DebugSingleStepConditionTest.java +++ b/core/camel-core/src/test/java/org/apache/camel/processor/interceptor/DebugSingleStepConditionTest.java @@ -80,7 +80,8 @@ public class DebugSingleStepConditionTest extends ContextTestSupport { return new RouteBuilder() { @Override public void configure() throws Exception { - // use debugger + // turn on debugging + context.setDebugging(true); context.setDebugger(new DefaultDebugger()); from("direct:start").routeId("foo").to("log:foo").to("log:bar").to("mock:result"); diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/interceptor/DebugSingleStepTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/interceptor/DebugSingleStepTest.java index 26f0971..f7fda32 100644 --- a/core/camel-core/src/test/java/org/apache/camel/processor/interceptor/DebugSingleStepTest.java +++ b/core/camel-core/src/test/java/org/apache/camel/processor/interceptor/DebugSingleStepTest.java @@ -75,7 +75,8 @@ public class DebugSingleStepTest extends ContextTestSupport { return new RouteBuilder() { @Override public void configure() throws Exception { - // use debugger + // turn on debugging + context.setDebugging(true); context.setDebugger(new DefaultDebugger()); from("direct:start").to("log:foo").to("log:bar").to("mock:result"); diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/interceptor/DebugTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/interceptor/DebugTest.java index 5b38485..7df10ca 100644 --- a/core/camel-core/src/test/java/org/apache/camel/processor/interceptor/DebugTest.java +++ b/core/camel-core/src/test/java/org/apache/camel/processor/interceptor/DebugTest.java @@ -184,7 +184,8 @@ public class DebugTest extends ContextTestSupport { return new RouteBuilder() { @Override public void configure() throws Exception { - // use debugger + // turn on debugging + context.setDebugging(true); context.setDebugger(new DefaultDebugger()); from("direct:start").to("log:foo").to("mock:result"); 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 331224f..cf30b0f 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 @@ -95,6 +95,7 @@ public abstract class BaseMainSupport extends BaseService { protected String defaultPropertyPlaceholderLocation = DEFAULT_PROPERTY_PLACEHOLDER_LOCATION; protected Properties initialProperties; protected Properties overrideProperties; + protected boolean standalone = true; private final MainHelper helper; protected BaseMainSupport() { @@ -407,11 +408,6 @@ public abstract class BaseMainSupport extends BaseService { autowireWildcardProperties(camelContext); } - // tracing may be enabled by some other property (i.e. camel.context.tracer.exchange-formatter.show-headers) - if (camelContext.isTracing() && !mainConfigurationProperties.isTracing()) { - camelContext.setTracing(Boolean.FALSE); - } - // log summary of configurations if (mainConfigurationProperties.isAutoConfigurationLogSummary() && !autoConfiguredProperties.isEmpty()) { LOG.info("Auto-configuration summary"); @@ -531,17 +527,20 @@ public abstract class BaseMainSupport extends BaseService { listener.beforeInitialize(this); } - // allow to do configuration before its started + // allow doing custom configuration before camel is started for (MainListener listener : listeners) { listener.beforeConfigure(this); } // we want to capture startup events for import tasks during main bootstrap StartupStepRecorder recorder = camelContext.adapt(ExtendedCamelContext.class).getStartupStepRecorder(); + StartupStep step; - StartupStep step = recorder.beginStep(BaseMainSupport.class, "autoconfigure", "Auto Configure"); - autoconfigure(camelContext); - recorder.endStep(step); + if (standalone) { + step = recorder.beginStep(BaseMainSupport.class, "autoconfigure", "Auto Configure"); + autoconfigure(camelContext); + recorder.endStep(step); + } if (mainConfigurationProperties.isEagerClassloading()) { step = recorder.beginStep(BaseMainSupport.class, "classloading", "Eager Classloading"); @@ -551,11 +550,13 @@ public abstract class BaseMainSupport extends BaseService { configureLifecycle(camelContext); - step = recorder.beginStep(BaseMainSupport.class, "configureRoutes", "Collect Routes"); - configureRoutes(camelContext); - recorder.endStep(step); + if (standalone) { + step = recorder.beginStep(BaseMainSupport.class, "configureRoutes", "Collect Routes"); + configureRoutes(camelContext); + recorder.endStep(step); + } - // allow to do configuration before its started + // allow doing custom configuration before camel is started for (MainListener listener : listeners) { listener.afterConfigure(this); listener.configure(camelContext); diff --git a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTracerMBean.java b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTracerMBean.java index 8b3f271..b5465a6 100644 --- a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTracerMBean.java +++ b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTracerMBean.java @@ -27,6 +27,9 @@ public interface ManagedTracerMBean { @ManagedAttribute(description = "Camel ManagementName") String getCamelManagementName(); + @ManagedAttribute(description = "Is tracing standby") + boolean isStandby(); + @ManagedAttribute(description = "Is tracing enabled") boolean isEnabled(); diff --git a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedTracer.java b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedTracer.java index 8aa90db..42f2fe5 100644 --- a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedTracer.java +++ b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedTracer.java @@ -59,6 +59,11 @@ public class ManagedTracer implements ManagedTracerMBean { } @Override + public boolean isStandby() { + return tracer.isStandby(); + } + + @Override public void setEnabled(boolean enabled) { tracer.setEnabled(enabled); }