Skip to content

Commit a3ee080

Browse files
committed
Avoid JMX access during boot when JMXFetch and Profiling are both disabled
1 parent 3e20b43 commit a3ee080

1 file changed

Lines changed: 90 additions & 44 deletions

File tree

  • dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap

dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java

Lines changed: 90 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -68,29 +68,38 @@ public class Agent {
6868
private static ClassLoader AGENT_CLASSLOADER = null;
6969
private static ClassLoader JMXFETCH_CLASSLOADER = null;
7070
private static ClassLoader PROFILING_CLASSLOADER = null;
71+
7172
private static volatile AgentTaskScheduler.Task<URL> PROFILER_INIT_AFTER_JMX = null;
7273

74+
private static boolean jmxFetchEnabled = true;
75+
private static boolean profilingEnabled = false;
76+
7377
public static void start(final Instrumentation inst, final URL bootstrapURL) {
7478
createParentClassloader(bootstrapURL);
7579

76-
if (!isOracleJDK8()) {
77-
// Profiling agent startup code is written in a way to allow `startProfilingAgent` be called
78-
// multiple times
79-
// If early profiling is enabled then this call will start profiling.
80-
// If early profiling is disabled then later call will do this.
81-
startProfilingAgent(bootstrapURL, true);
82-
} else {
83-
log.debug("Oracle JDK 8 detected. Delaying profiler initialization.");
84-
// Profiling can not run early on Oracle JDK 8 because it will cause JFR initialization
85-
// deadlock.
86-
// Oracle JDK 8 JFR controller requires JMX so register an 'after-jmx-initialized' callback.
87-
PROFILER_INIT_AFTER_JMX =
88-
new AgentTaskScheduler.Task<URL>() {
89-
@Override
90-
public void run(URL target) {
91-
startProfilingAgent(target, false);
92-
}
93-
};
80+
jmxFetchEnabled = isJmxFetchEnabled();
81+
profilingEnabled = isProfilingEnabled();
82+
83+
if (profilingEnabled) {
84+
if (!isOracleJDK8()) {
85+
// Profiling agent startup code is written in a way to allow `startProfilingAgent` be called
86+
// multiple times
87+
// If early profiling is enabled then this call will start profiling.
88+
// If early profiling is disabled then later call will do this.
89+
startProfilingAgent(bootstrapURL, true);
90+
} else {
91+
log.debug("Oracle JDK 8 detected. Delaying profiler initialization.");
92+
// Profiling can not run early on Oracle JDK 8 because it will cause JFR initialization
93+
// deadlock.
94+
// Oracle JDK 8 JFR controller requires JMX so register an 'after-jmx-initialized' callback.
95+
PROFILER_INIT_AFTER_JMX =
96+
new AgentTaskScheduler.Task<URL>() {
97+
@Override
98+
public void run(URL target) {
99+
startProfilingAgent(target, false);
100+
}
101+
};
102+
}
94103
}
95104

96105
/*
@@ -122,17 +131,19 @@ public void run(URL target) {
122131
* JMXFetch until we detect the custom MBeanServerBuilder is being used. This takes precedence over the custom
123132
* log manager check because any custom log manager will be installed before any custom MBeanServerBuilder.
124133
*/
125-
int jmxStartDelay = getJmxStartDelay();
126-
if (appUsingCustomJMXBuilder) {
127-
log.debug("Custom JMX builder detected. Delaying JMXFetch initialization.");
128-
registerMBeanServerBuilderCallback(new StartJmxCallback(bootstrapURL, jmxStartDelay));
129-
// one minute fail-safe in case nothing touches JMX and and callback isn't triggered
130-
scheduleJmxStart(bootstrapURL, 60 + jmxStartDelay);
131-
} else if (appUsingCustomLogManager) {
132-
log.debug("Custom logger detected. Delaying JMXFetch initialization.");
133-
registerLogManagerCallback(new StartJmxCallback(bootstrapURL, jmxStartDelay));
134-
} else {
135-
scheduleJmxStart(bootstrapURL, jmxStartDelay);
134+
if (jmxFetchEnabled || profilingEnabled) { // both features use JMX
135+
int jmxStartDelay = getJmxStartDelay();
136+
if (appUsingCustomJMXBuilder) {
137+
log.debug("Custom JMX builder detected. Delaying JMXFetch initialization.");
138+
registerMBeanServerBuilderCallback(new StartJmxCallback(bootstrapURL, jmxStartDelay, true));
139+
// one minute fail-safe in case nothing touches JMX and and callback isn't triggered
140+
scheduleJmxStart(bootstrapURL, 60 + jmxStartDelay);
141+
} else if (appUsingCustomLogManager) {
142+
log.debug("Custom logger detected. Delaying JMXFetch initialization.");
143+
registerLogManagerCallback(new StartJmxCallback(bootstrapURL, jmxStartDelay, false));
144+
} else {
145+
scheduleJmxStart(bootstrapURL, jmxStartDelay);
146+
}
136147
}
137148

138149
/*
@@ -150,7 +161,7 @@ public void run(URL target) {
150161
/*
151162
* Similar thing happens with Profiler on zulu-8 because it is using OkHttp which indirectly loads JFR events which in turn loads LogManager. This is not a problem on newer JDKs because there JFR uses different logging facility.
152163
*/
153-
if (!isOracleJDK8()) {
164+
if (profilingEnabled && !isOracleJDK8()) {
154165
if (!isJavaVersionAtLeast(9) && appUsingCustomLogManager) {
155166
log.debug("Custom logger detected. Delaying JMXFetch initialization.");
156167
registerLogManagerCallback(new StartProfilingAgentCallback(inst, bootstrapURL));
@@ -229,10 +240,13 @@ public void run() {
229240

230241
protected static class StartJmxCallback extends ClassLoadCallBack {
231242
private final int jmxStartDelay;
243+
private final boolean customJmxBuilder;
232244

233-
StartJmxCallback(final URL bootstrapURL, final int jmxStartDelay) {
245+
StartJmxCallback(
246+
final URL bootstrapURL, final int jmxStartDelay, final boolean customJmxBuilder) {
234247
super(bootstrapURL);
235248
this.jmxStartDelay = jmxStartDelay;
249+
this.customJmxBuilder = customJmxBuilder;
236250
}
237251

238252
@Override
@@ -242,8 +256,14 @@ public AgentThread agentThread() {
242256

243257
@Override
244258
public void execute() {
245-
// finish building platform JMX from context of custom builder before starting JMXFetch
246-
ManagementFactory.getPlatformMBeanServer();
259+
if (customJmxBuilder) {
260+
try {
261+
// finish building platform JMX from context of custom builder before starting JMXFetch
262+
ManagementFactory.getPlatformMBeanServer();
263+
} catch (Throwable e) {
264+
log.error("Error loading custom MBeanServerBuilder", e);
265+
}
266+
}
247267
scheduleJmxStart(bootstrapURL, jmxStartDelay);
248268
}
249269
}
@@ -363,19 +383,23 @@ private static synchronized void startJmx(final URL bootstrapURL) {
363383
if (jmxStarting.getAndSet(true)) {
364384
return; // another thread is already in startJmx
365385
}
366-
startJmxFetch(bootstrapURL);
386+
if (jmxFetchEnabled) {
387+
startJmxFetch(bootstrapURL);
388+
}
367389
initializeJmxSystemAccessProvider(AGENT_CLASSLOADER);
368-
registerDeadlockDetectionEvent(bootstrapURL);
369-
if (PROFILER_INIT_AFTER_JMX != null) {
370-
if (getJmxStartDelay() == 0) {
371-
log.debug("Waiting for profiler initialization");
372-
AgentTaskScheduler.INSTANCE.scheduleWithJitter(
373-
PROFILER_INIT_AFTER_JMX, bootstrapURL, 500, TimeUnit.MILLISECONDS);
374-
} else {
375-
log.debug("Initializing profiler");
376-
PROFILER_INIT_AFTER_JMX.run(bootstrapURL);
390+
if (profilingEnabled) {
391+
registerDeadlockDetectionEvent(bootstrapURL);
392+
if (PROFILER_INIT_AFTER_JMX != null) {
393+
if (getJmxStartDelay() == 0) {
394+
log.debug("Waiting for profiler initialization");
395+
AgentTaskScheduler.INSTANCE.scheduleWithJitter(
396+
PROFILER_INIT_AFTER_JMX, bootstrapURL, 500, TimeUnit.MILLISECONDS);
397+
} else {
398+
log.debug("Initializing profiler");
399+
PROFILER_INIT_AFTER_JMX.run(bootstrapURL);
400+
}
401+
PROFILER_INIT_AFTER_JMX = null;
377402
}
378-
PROFILER_INIT_AFTER_JMX = null;
379403
}
380404
}
381405

@@ -619,6 +643,28 @@ private static boolean isStartupLogsEnabled() {
619643
return !"false".equalsIgnoreCase(startupLogsEnabled);
620644
}
621645

646+
/** @return {@code true} if JMXFetch is enabled */
647+
private static boolean isJmxFetchEnabled() {
648+
final String jmxFetchEnabledSysprop = "dd.jmxfetch.enabled";
649+
String jmxFetchEnabled = System.getProperty(jmxFetchEnabledSysprop);
650+
if (jmxFetchEnabled == null) {
651+
jmxFetchEnabled = ddGetEnv(jmxFetchEnabledSysprop);
652+
}
653+
// assume true unless it's explicitly set to "false"
654+
return !"false".equalsIgnoreCase(jmxFetchEnabled);
655+
}
656+
657+
/** @return {@code true} if profiling is enabled */
658+
private static boolean isProfilingEnabled() {
659+
final String profilingEnabledSysprop = "dd.profiling.enabled";
660+
String profilingEnabled = System.getProperty(profilingEnabledSysprop);
661+
if (profilingEnabled == null) {
662+
profilingEnabled = ddGetEnv(profilingEnabledSysprop);
663+
}
664+
// assume false unless it's explicitly set to "true"
665+
return "true".equalsIgnoreCase(profilingEnabled);
666+
}
667+
622668
/** @return configured JMX start delay in seconds */
623669
private static int getJmxStartDelay() {
624670
String startDelay = ddGetProperty("dd.dogstatsd.start-delay");

0 commit comments

Comments
 (0)