Fix race conditions in custom log manager test
Fix two race conditions in the custom log manager test.
Remove possibility of false positives by blocking until jmx thread
sends statsd metrics
Disable logging in test to avoid deadlock in jmxfetch which can
occur when the JVM shuts down too quickly
MODIFY
dd-java-agent/src/test/groovy/datadog/trace/agent/CustomLogManagerTest.groovy
dd-java-agent/src/test/groovy/datadog/trace/agent/CustomLogManagerTest.groovy
@@ -26,7 +26,7 @@ class CustomLogManagerTest extends Specification {
expect:
agentArg != null
IntegrationTestUtils.runOnSeparateJvm(LogManagerSetter.getName()
- , [agentArg, "-javaagent:" + customAgent.getPath(), "-Ddd.jmxfetch.enabled=true"] as String[]
+ , ["-javaagent:" + customAgent.getPath(), agentArg, "-Ddd.jmxfetch.enabled=true", "-Ddd.jmxfetch.refresh-beans-period=1", "-Ddatadog.slf4j.simpleLogger.defaultLogLevel=off"] as String[]
, "" as String[]
, true) == 0
}

MODIFY
dd-java-agent/src/test/java/jvmbootstraptest/LogManagerSetter.java
dd-java-agent/src/test/java/jvmbootstraptest/LogManagerSetter.java
package jvmbootstraptest;
-import java.lang.instrument.ClassFileTransformer;
-import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
-import java.security.ProtectionDomain;
-import java.util.concurrent.atomic.AtomicBoolean;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.SocketException;
import java.util.logging.LogManager;
public class LogManagerSetter {
- // Intentionally doing the string replace to bypass gradle shadow rename
- // loggerClassName = java.util.logging.Logger
- private static final String loggerClassName =
- "java.util.logging.TMP".replaceFirst("TMP", "Logger");
- private static final String loggerInternalName = loggerClassName.replace('.', '/');
- private static final AtomicBoolean loggerInitialized = new AtomicBoolean(false);
+ private static final DatagramSocket socket;
+ private static final int localPort;
+
+ static {
+ try {
+ socket = new DatagramSocket(0);
+ localPort = socket.getLocalPort();
+ } catch (SocketException e) {
+ throw new RuntimeException(e);
+ }
+ }
public static void premain(final String agentArgs, final Instrumentation inst) throws Exception {
- inst.addTransformer(
- new ClassFileTransformer() {
- @Override
- public byte[] transform(
- ClassLoader loader,
- String className,
- Class<?> classBeingRedefined,
- ProtectionDomain protectionDomain,
- byte[] classfileBuffer)
- throws IllegalClassFormatException {
- if (loggerInternalName.equals(className)) {
- loggerInitialized.compareAndSet(false, true);
- }
- return null;
- }
- });
+ // set jmxfetch port in premain before tracer's premain runs
+ System.setProperty("dd.jmxfetch.statsd.port", Integer.toString(localPort));
+ System.setProperty("dd.jmxfetch.statsd.host", "localhost");
}
public static void main(String... args) throws Exception {
- final ClassLoader systemLoader = ClassLoader.getSystemClassLoader();
-
- // once the logger class has been initialized, we know jmxfetch is running and can proceed with
- // the test
- while (!loggerInitialized.get()) {
- Thread.sleep(1);
+ try {
+ // block until jmxfetch sends data
+ final byte[] buf = new byte[1500];
+ final DatagramPacket packet = new DatagramPacket(buf, buf.length);
+ socket.receive(packet);
+ } finally {
+ socket.close();
}
- systemLoader.loadClass(loggerClassName);
- // at this point the logger is loaded and fully initialized
-
System.setProperty("java.util.logging.manager", CustomLogManager.class.getName());
customAssert(
LogManager.getLogManager().getClass(),

Fix race conditions in custom log manager test

Fix two race conditions in the custom log manager test.

- Remove possibility of false positives by blocking until jmx thread
  sends statsd metrics
- Disable logging in test to avoid deadlock in jmxfetch which can
  occur when the JVM shuts down too quickly