diff --git a/agent/src/main/java/io/pyroscope/javaagent/PyroscopeAgent.java b/agent/src/main/java/io/pyroscope/javaagent/PyroscopeAgent.java index c226a44..6de5f0a 100644 --- a/agent/src/main/java/io/pyroscope/javaagent/PyroscopeAgent.java +++ b/agent/src/main/java/io/pyroscope/javaagent/PyroscopeAgent.java @@ -35,6 +35,12 @@ public static void start(Config config) { public static void start(Options options) { Logger logger = options.logger; + + if (!options.config.agentEnabled) { + logger.log(Logger.Level.INFO, "Pyroscope agent start disabled by configuration"); + return; + } + if (!started.compareAndSet(false, true)) { logger.log(Logger.Level.ERROR, "Failed to start profiling - already started"); return; diff --git a/agent/src/main/java/io/pyroscope/javaagent/config/Config.java b/agent/src/main/java/io/pyroscope/javaagent/config/Config.java index e54510e..1e4f0bf 100644 --- a/agent/src/main/java/io/pyroscope/javaagent/config/Config.java +++ b/agent/src/main/java/io/pyroscope/javaagent/config/Config.java @@ -25,6 +25,7 @@ * through pyroscope.properties file or System.getevn - see io.pyroscope.javaagent.impl.DefaultConfigurationProvider */ public final class Config { + private static final String PYROSCOPE_AGENT_ENABLED_CONFIG = "PYROSCOPE_AGENT_ENABLED"; private static final String PYROSCOPE_APPLICATION_NAME_CONFIG = "PYROSCOPE_APPLICATION_NAME"; private static final String PYROSCOPE_PROFILING_INTERVAL_CONFIG = "PYROSCOPE_PROFILING_INTERVAL"; private static final String PYROSCOPE_PROFILER_EVENT_CONFIG = "PYROSCOPE_PROFILER_EVENT"; @@ -65,6 +66,7 @@ public final class Config { */ private static final String PYROSCOPE_SAMPLING_EVENT_ORDER_CONFIG = "PYROSCOPE_SAMPLING_EVENT_ORDER"; + private static final boolean DEFAULT_AGENT_ENABLED = true; public static final String DEFAULT_SPY_NAME = "javaspy"; private static final Duration DEFAULT_PROFILING_INTERVAL = Duration.ofMillis(10); private static final EventType DEFAULT_PROFILER_EVENT = EventType.ITIMER; @@ -85,6 +87,7 @@ public final class Config { private static final boolean DEFAULT_GC_BEFORE_DUMP = false; private static final Duration DEFAULT_SAMPLING_DURATION = null; + public final boolean agentEnabled; public final String applicationName; public final Duration profilingInterval; public final EventType profilingEvent; @@ -118,7 +121,8 @@ public final class Config { public final String basicAuthUser; public final String basicAuthPassword; - Config(final String applicationName, + Config(final boolean agentEnabled, + final String applicationName, final Duration profilingInterval, final EventType profilingEvent, final String profilingAlloc, @@ -144,6 +148,7 @@ public final class Config { String APExtraArguments, String basicAuthUser, String basicAuthPassword) { + this.agentEnabled = agentEnabled; this.applicationName = applicationName; this.profilingInterval = profilingInterval; this.profilingEvent = profilingEvent; @@ -200,7 +205,8 @@ public long profilingIntervalInHertz() { @Override public String toString() { return "Config{" + - "applicationName='" + applicationName + '\'' + + "agentEnabled=" + agentEnabled + + ", applicationName='" + applicationName + '\'' + ", profilingInterval=" + profilingInterval + ", profilingEvent=" + profilingEvent + ", profilingAlloc='" + profilingAlloc + '\'' + @@ -241,6 +247,7 @@ public static Config build() { public static Config build(ConfigurationProvider cp) { String alloc = profilingAlloc(cp); + boolean agentEnabled = bool(cp, PYROSCOPE_AGENT_ENABLED_CONFIG, DEFAULT_AGENT_ENABLED); boolean allocLive = bool(cp, PYROSCOPE_ALLOC_LIVE, DEFAULT_ALLOC_LIVE); if (DEFAULT_PROFILER_ALLOC.equals(alloc) && allocLive) { DefaultLogger.PRECONFIG_LOGGER.log(Logger.Level.WARN, "%s is ignored because %s is not configured", @@ -248,6 +255,7 @@ public static Config build(ConfigurationProvider cp) { allocLive = false; } return new Config( + agentEnabled, applicationName(cp), profilingInterval(cp), profilingEvent(cp), @@ -630,6 +638,7 @@ private static Duration samplingDuration(ConfigurationProvider configurationProv } public static class Builder { + public boolean agentEnabled = DEFAULT_AGENT_ENABLED; public String applicationName = null; public Duration profilingInterval = DEFAULT_PROFILING_INTERVAL; public EventType profilingEvent = DEFAULT_PROFILER_EVENT; @@ -662,6 +671,7 @@ public Builder() { } public Builder(Config buildUpon) { + agentEnabled = buildUpon.agentEnabled; applicationName = buildUpon.applicationName; profilingInterval = buildUpon.profilingInterval; profilingEvent = buildUpon.profilingEvent; @@ -688,6 +698,11 @@ public Builder(Config buildUpon) { basicAuthPassword = buildUpon.basicAuthPassword; } + public Builder setAgentEnabled(boolean agentEnabled) { + this.agentEnabled = agentEnabled; + return this; + } + public Builder setApplicationName(String applicationName) { this.applicationName = applicationName; return this; @@ -827,7 +842,8 @@ public Config build() { if (applicationName == null || applicationName.isEmpty()) { applicationName = generateApplicationName(); } - return new Config(applicationName, + return new Config(agentEnabled, + applicationName, profilingInterval, profilingEvent, profilingAlloc, diff --git a/agent/src/test/java/io/pyroscope/javaagent/PyroscopeAgentTest.java b/agent/src/test/java/io/pyroscope/javaagent/PyroscopeAgentTest.java new file mode 100644 index 0000000..15fcda3 --- /dev/null +++ b/agent/src/test/java/io/pyroscope/javaagent/PyroscopeAgentTest.java @@ -0,0 +1,61 @@ +package io.pyroscope.javaagent; + +import io.pyroscope.javaagent.api.Logger; +import io.pyroscope.javaagent.api.ProfilingScheduler; +import io.pyroscope.javaagent.config.Config; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +public class PyroscopeAgentTest { + + private Config configAgentEnabled; + private Config configAgentDisabled; + private PyroscopeAgent.Options optionsAgentEnabled; + private PyroscopeAgent.Options optionsAgentDisabled; + + @Mock + private Logger logger; + + @Mock + private ProfilingScheduler profilingScheduler; + + @BeforeEach + void setUp() { + configAgentEnabled = new Config.Builder() + .setAgentEnabled(true) + .build(); + optionsAgentEnabled = new PyroscopeAgent.Options.Builder(configAgentEnabled) + .setScheduler(profilingScheduler) + .setLogger(logger) + .build(); + + configAgentDisabled = new Config.Builder() + .setAgentEnabled(false) + .build(); + optionsAgentDisabled = new PyroscopeAgent.Options.Builder(configAgentDisabled) + .setScheduler(profilingScheduler) + .setLogger(logger) + .build(); + } + + @Test + void startupTestWithEnabledAgent() { + PyroscopeAgent.start(optionsAgentEnabled); + + verify(profilingScheduler, times(1)).start(any()); + } + + @Test + void startupTestWithDisabledAgent() { + PyroscopeAgent.start(optionsAgentDisabled); + + verify(profilingScheduler, never()).start(any()); + } +} \ No newline at end of file