diff --git a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java index 3e737c3618..2ffc541f6e 100644 --- a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java +++ b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java @@ -47,6 +47,10 @@ public class Agent { public static void start(final Instrumentation inst, final URL bootstrapURL) { createParentClassloader(bootstrapURL); + // Profiling agent startup code is written in a way to allow `startProfilingAgent` be called + // multiple times + // If early profiling is enabled then this call will start profiling. + // If early profiling is disabled then later call will do this. startProfilingAgent(bootstrapURL, true); startDatadogAgent(inst, bootstrapURL); @@ -279,7 +283,7 @@ public class Agent { } private static synchronized void startProfilingAgent( - final URL bootstrapURL, final boolean early) { + final URL bootstrapURL, final boolean isStartingFirst) { final ClassLoader contextLoader = Thread.currentThread().getContextClassLoader(); try { if (PROFILING_CLASSLOADER == null) { @@ -290,7 +294,7 @@ public class Agent { final Class profilingAgentClass = PROFILING_CLASSLOADER.loadClass("com.datadog.profiling.agent.ProfilingAgent"); final Method profilingInstallerMethod = profilingAgentClass.getMethod("run", Boolean.TYPE); - profilingInstallerMethod.invoke(null, early); + profilingInstallerMethod.invoke(null, isStartingFirst); } catch (final ClassFormatError e) { /* Profiling is compiled for Java8. Loading it on Java7 results in ClassFormatError diff --git a/dd-java-agent/agent-profiling/profiling-controller/src/main/java/com/datadog/profiling/controller/ProfilingSystem.java b/dd-java-agent/agent-profiling/profiling-controller/src/main/java/com/datadog/profiling/controller/ProfilingSystem.java index d6a95fa84d..ee2196fc68 100644 --- a/dd-java-agent/agent-profiling/profiling-controller/src/main/java/com/datadog/profiling/controller/ProfilingSystem.java +++ b/dd-java-agent/agent-profiling/profiling-controller/src/main/java/com/datadog/profiling/controller/ProfilingSystem.java @@ -38,7 +38,7 @@ public final class ProfilingSystem { private final Duration startupDelay; private final Duration uploadPeriod; - private final boolean forceEarly; + private final boolean isStartingFirst; private OngoingRecording recording; private boolean started = false; @@ -51,6 +51,7 @@ public final class ProfilingSystem { * @param startupDelay delay before starting jfr * @param startupDelayRandomRange randomization range for startup delay * @param uploadPeriod how often to upload data + * @param isStartingFirst starting profiling before other tools * @throws ConfigurationException if the configuration information was bad. */ public ProfilingSystem( @@ -59,7 +60,7 @@ public final class ProfilingSystem { final Duration startupDelay, final Duration startupDelayRandomRange, final Duration uploadPeriod, - final boolean forceEarly) + final boolean isStartingFirst) throws ConfigurationException { this( controller, @@ -67,7 +68,7 @@ public final class ProfilingSystem { startupDelay, startupDelayRandomRange, uploadPeriod, - forceEarly, + isStartingFirst, Executors.newScheduledThreadPool( 1, new ProfilingThreadFactory("dd-profiler-recording-scheduler")), ThreadLocalRandom.current()); @@ -79,14 +80,14 @@ public final class ProfilingSystem { final Duration baseStartupDelay, final Duration startupDelayRandomRange, final Duration uploadPeriod, - final boolean forceEarly, + final boolean isStartingFirst, final ScheduledExecutorService executorService, final ThreadLocalRandom threadLocalRandom) throws ConfigurationException { this.controller = controller; this.dataListener = dataListener; this.uploadPeriod = uploadPeriod; - this.forceEarly = forceEarly; + this.isStartingFirst = isStartingFirst; this.executorService = executorService; if (baseStartupDelay.isNegative()) { @@ -108,12 +109,12 @@ public final class ProfilingSystem { public final void start() { log.info( - "Starting profiling system: startupDelay={}ms, uploadPeriod={}ms, forceEarly={}", + "Starting profiling system: startupDelay={}ms, uploadPeriod={}ms, isStartingFirst={}", startupDelay.toMillis(), uploadPeriod.toMillis(), - forceEarly); + isStartingFirst); - if (forceEarly) { + if (isStartingFirst) { startProfilingRecording(); } else { // Delay JFR initialization. This code is run from 'premain' and there is a known bug in JVM diff --git a/dd-java-agent/agent-profiling/src/main/java/com/datadog/profiling/agent/ProfilingAgent.java b/dd-java-agent/agent-profiling/src/main/java/com/datadog/profiling/agent/ProfilingAgent.java index d4a878e994..d6d8cb0147 100644 --- a/dd-java-agent/agent-profiling/src/main/java/com/datadog/profiling/agent/ProfilingAgent.java +++ b/dd-java-agent/agent-profiling/src/main/java/com/datadog/profiling/agent/ProfilingAgent.java @@ -19,13 +19,14 @@ public class ProfilingAgent { /** * Main entry point into profiling Note: this must be reentrant because we may want to start - * profiling early, and then attempt to start it again at normal time + * profiling before any other tool, and then attempt to start it again at normal time */ - public static synchronized void run(final boolean early) throws IllegalArgumentException { + public static synchronized void run(final boolean isStartingFirst) + throws IllegalArgumentException { if (PROFILER == null) { final Config config = Config.get(); - if (early && !config.isProfilingStartForceEarly()) { - log.info("Profiling: not starting early"); + if (isStartingFirst && !config.isProfilingStartForceFirst()) { + log.info("Profiling: not starting first"); // early startup is disabled; return; } @@ -57,7 +58,7 @@ public class ProfilingAgent { startupDelay, startupDelayRandomRange, uploadPeriod, - config.isProfilingStartForceEarly()); + config.isProfilingStartForceFirst()); PROFILER.start(); log.info("Profiling has started!"); diff --git a/dd-trace-api/src/main/java/datadog/trace/api/Config.java b/dd-trace-api/src/main/java/datadog/trace/api/Config.java index 237703aaf7..a53f58c2d0 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/Config.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/Config.java @@ -116,8 +116,8 @@ public class Config { public static final String PROFILING_START_DELAY = "profiling.start-delay"; // DANGEROUS! May lead on sigsegv on JVMs before 14 // Not intended for production use - public static final String PROFILING_START_FORCE_EARLY = - "profiling.experimental.start-force-early"; + public static final String PROFILING_START_FORCE_FIRST = + "profiling.experimental.start-force-first"; public static final String PROFILING_UPLOAD_PERIOD = "profiling.upload.period"; public static final String PROFILING_TEMPLATE_OVERRIDE_FILE = "profiling.jfr-template-override-file"; @@ -176,7 +176,7 @@ public class Config { public static final String DEFAULT_PROFILING_URL = "https://intake.profile.datadoghq.com/v1/input"; public static final int DEFAULT_PROFILING_START_DELAY = 10; - public static final boolean DEFAULT_PROFILING_START_FORCE_EARLY = false; + public static final boolean DEFAULT_PROFILING_START_FORCE_FIRST = false; public static final int DEFAULT_PROFILING_UPLOAD_PERIOD = 60; // 1 min public static final int DEFAULT_PROFILING_UPLOAD_TIMEOUT = 30; // seconds public static final String DEFAULT_PROFILING_UPLOAD_COMPRESSION = "on"; @@ -273,7 +273,7 @@ public class Config { @Getter private final String profilingApiKey; private final Map profilingTags; @Getter private final int profilingStartDelay; - @Getter private final boolean profilingStartForceEarly; + @Getter private final boolean profilingStartForceFirst; @Getter private final int profilingUploadPeriod; @Getter private final String profilingTemplateOverrideFile; @Getter private final int profilingUploadTimeout; @@ -452,9 +452,9 @@ public class Config { profilingTags = getMapSettingFromEnvironment(PROFILING_TAGS, null); profilingStartDelay = getIntegerSettingFromEnvironment(PROFILING_START_DELAY, DEFAULT_PROFILING_START_DELAY); - profilingStartForceEarly = + profilingStartForceFirst = getBooleanSettingFromEnvironment( - PROFILING_START_FORCE_EARLY, DEFAULT_PROFILING_START_FORCE_EARLY); + PROFILING_START_FORCE_FIRST, DEFAULT_PROFILING_START_FORCE_FIRST); profilingUploadPeriod = getIntegerSettingFromEnvironment(PROFILING_UPLOAD_PERIOD, DEFAULT_PROFILING_UPLOAD_PERIOD); profilingTemplateOverrideFile = @@ -614,9 +614,9 @@ public class Config { profilingTags = getPropertyMapValue(properties, PROFILING_TAGS, parent.profilingTags); profilingStartDelay = getPropertyIntegerValue(properties, PROFILING_START_DELAY, parent.profilingStartDelay); - profilingStartForceEarly = + profilingStartForceFirst = getPropertyBooleanValue( - properties, PROFILING_START_FORCE_EARLY, parent.profilingStartForceEarly); + properties, PROFILING_START_FORCE_FIRST, parent.profilingStartForceFirst); profilingUploadPeriod = getPropertyIntegerValue(properties, PROFILING_UPLOAD_PERIOD, parent.profilingUploadPeriod); profilingTemplateOverrideFile = diff --git a/dd-trace-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy b/dd-trace-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy index da4fdcb0dd..db37f07a6a 100644 --- a/dd-trace-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy +++ b/dd-trace-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy @@ -41,7 +41,7 @@ import static datadog.trace.api.Config.PROFILING_PROXY_PASSWORD import static datadog.trace.api.Config.PROFILING_PROXY_PORT import static datadog.trace.api.Config.PROFILING_PROXY_USERNAME import static datadog.trace.api.Config.PROFILING_START_DELAY -import static datadog.trace.api.Config.PROFILING_START_FORCE_EARLY +import static datadog.trace.api.Config.PROFILING_START_FORCE_FIRST import static datadog.trace.api.Config.PROFILING_TAGS import static datadog.trace.api.Config.PROFILING_TEMPLATE_OVERRIDE_FILE import static datadog.trace.api.Config.PROFILING_UPLOAD_COMPRESSION @@ -137,7 +137,7 @@ class ConfigTest extends DDSpecification { config.profilingApiKey == null config.mergedProfilingTags == [(HOST_TAG): config.getHostName(), (RUNTIME_ID_TAG): config.getRuntimeId(), (SERVICE_TAG): config.serviceName, (LANGUAGE_TAG_KEY): LANGUAGE_TAG_VALUE] config.profilingStartDelay == 10 - config.profilingStartForceEarly == false + config.profilingStartForceFirst == false config.profilingUploadPeriod == 60 config.profilingTemplateOverrideFile == null config.profilingUploadTimeout == 30 @@ -202,7 +202,7 @@ class ConfigTest extends DDSpecification { prop.setProperty(PROFILING_API_KEY, "new api key") prop.setProperty(PROFILING_TAGS, "f:6,host:test-host") prop.setProperty(PROFILING_START_DELAY, "1111") - prop.setProperty(PROFILING_START_FORCE_EARLY, "true") + prop.setProperty(PROFILING_START_FORCE_FIRST, "true") prop.setProperty(PROFILING_UPLOAD_PERIOD, "1112") prop.setProperty(PROFILING_TEMPLATE_OVERRIDE_FILE, "/path") prop.setProperty(PROFILING_UPLOAD_TIMEOUT, "1116") @@ -258,7 +258,7 @@ class ConfigTest extends DDSpecification { config.profilingApiKey == "new api key" // we can still override via internal properties object config.mergedProfilingTags == [b: "2", f: "6", (HOST_TAG): "test-host", (RUNTIME_ID_TAG): config.getRuntimeId(), (SERVICE_TAG): config.serviceName, (LANGUAGE_TAG_KEY): LANGUAGE_TAG_VALUE] config.profilingStartDelay == 1111 - config.profilingStartForceEarly == true + config.profilingStartForceFirst == true config.profilingUploadPeriod == 1112 config.profilingUploadCompression == "off" config.profilingTemplateOverrideFile == "/path" @@ -314,7 +314,7 @@ class ConfigTest extends DDSpecification { System.setProperty(PREFIX + PROFILING_API_KEY, "new api key") System.setProperty(PREFIX + PROFILING_TAGS, "f:6,host:test-host") System.setProperty(PREFIX + PROFILING_START_DELAY, "1111") - System.setProperty(PREFIX + PROFILING_START_FORCE_EARLY, "true") + System.setProperty(PREFIX + PROFILING_START_FORCE_FIRST, "true") System.setProperty(PREFIX + PROFILING_UPLOAD_PERIOD, "1112") System.setProperty(PREFIX + PROFILING_TEMPLATE_OVERRIDE_FILE, "/path") System.setProperty(PREFIX + PROFILING_UPLOAD_TIMEOUT, "1116") @@ -370,7 +370,7 @@ class ConfigTest extends DDSpecification { config.profilingApiKey == null // system properties cannot be used to provide a key config.mergedProfilingTags == [b: "2", f: "6", (HOST_TAG): "test-host", (RUNTIME_ID_TAG): config.getRuntimeId(), (SERVICE_TAG): config.serviceName, (LANGUAGE_TAG_KEY): LANGUAGE_TAG_VALUE] config.profilingStartDelay == 1111 - config.profilingStartForceEarly == true + config.profilingStartForceFirst == true config.profilingUploadPeriod == 1112 config.profilingTemplateOverrideFile == "/path" config.profilingUploadTimeout == 1116