diff --git a/dd-java-agent/instrumentation/java-concurrent/java-concurrent-21/build.gradle b/dd-java-agent/instrumentation/java-concurrent/java-concurrent-21/build.gradle index 361477f06ff..6c1b1ff4afc 100644 --- a/dd-java-agent/instrumentation/java-concurrent/java-concurrent-21/build.gradle +++ b/dd-java-agent/instrumentation/java-concurrent/java-concurrent-21/build.gradle @@ -6,6 +6,8 @@ ext { } apply from: "$rootDir/gradle/java.gradle" +// Use slf4j-simple as default; logback has a high chance of getting stuck in a deadlock on CI. +apply from: "$rootDir/gradle/slf4j-simple.gradle" apply plugin: 'idea' muzzle { diff --git a/dd-java-agent/instrumentation/java-concurrent/java-concurrent-21/src/test/groovy/VirtualThreadTest.groovy b/dd-java-agent/instrumentation/java-concurrent/java-concurrent-21/src/test/groovy/VirtualThreadTest.groovy index ccd652dfc81..9ace7d7f467 100644 --- a/dd-java-agent/instrumentation/java-concurrent/java-concurrent-21/src/test/groovy/VirtualThreadTest.groovy +++ b/dd-java-agent/instrumentation/java-concurrent/java-concurrent-21/src/test/groovy/VirtualThreadTest.groovy @@ -59,17 +59,15 @@ class VirtualThreadTest extends AgentTestRunner { } where: - // spotless:off - name | method | poolImpl - "execute Runnable" | executeRunnable | Executors.newVirtualThreadPerTaskExecutor() - "submit Runnable" | submitRunnable | Executors.newVirtualThreadPerTaskExecutor() - "submit Callable" | submitCallable | Executors.newVirtualThreadPerTaskExecutor() + name | method | poolImpl + "execute Runnable" | executeRunnable | Executors.newVirtualThreadPerTaskExecutor() + "submit Runnable" | submitRunnable | Executors.newVirtualThreadPerTaskExecutor() + "submit Callable" | submitCallable | Executors.newVirtualThreadPerTaskExecutor() "submit Runnable ECS" | submitRunnableExecutorCompletionService | new ExecutorCompletionService<>(Executors.newVirtualThreadPerTaskExecutor()) - "submit Callable ECS" | submitCallable | new ExecutorCompletionService<>(Executors.newVirtualThreadPerTaskExecutor()) - "invokeAll" | invokeAll | Executors.newVirtualThreadPerTaskExecutor() - "invokeAll with timeout" | invokeAllTimeout | Executors.newVirtualThreadPerTaskExecutor() - "invokeAny" | invokeAny | Executors.newVirtualThreadPerTaskExecutor() - "invokeAny with timeout" | invokeAnyTimeout | Executors.newVirtualThreadPerTaskExecutor() - // spotless:on + "submit Callable ECS" | submitCallable | new ExecutorCompletionService<>(Executors.newVirtualThreadPerTaskExecutor()) + "invokeAll" | invokeAll | Executors.newVirtualThreadPerTaskExecutor() + "invokeAll with timeout" | invokeAllTimeout | Executors.newVirtualThreadPerTaskExecutor() + "invokeAny" | invokeAny | Executors.newVirtualThreadPerTaskExecutor() + "invokeAny with timeout" | invokeAnyTimeout | Executors.newVirtualThreadPerTaskExecutor() } } diff --git a/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/AgentTestRunner.groovy b/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/AgentTestRunner.groovy index 8c70e25d876..20fe0333b4d 100644 --- a/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/AgentTestRunner.groovy +++ b/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/AgentTestRunner.groovy @@ -1,7 +1,6 @@ package datadog.trace.agent.test import ch.qos.logback.classic.Level -import ch.qos.logback.classic.Logger import ch.qos.logback.classic.util.ContextInitializer import com.datadog.debugger.agent.ClassesToRetransformFinder import com.datadog.debugger.agent.Configuration @@ -68,6 +67,7 @@ import net.bytebuddy.utility.JavaModule import okhttp3.HttpUrl import okhttp3.OkHttpClient import org.junit.runner.RunWith +import org.slf4j.Logger import org.slf4j.LoggerFactory import org.spockframework.mock.MockUtil import org.spockframework.mock.runtime.MockInvocation @@ -289,12 +289,16 @@ abstract class AgentTestRunner extends DDSpecification implements AgentBuilder.L true } + @SuppressForbidden private static void configureLoggingLevels() { def logger = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME) - if (!(logger instanceof Logger)) { + + // Check logger class by name to avoid NoClassDefFoundError at runtime for tests without Logback. + if (logger.class.name != "ch.qos.logback.classic.Logger") { return } - final Logger rootLogger = logger + + final ch.qos.logback.classic.Logger rootLogger = (ch.qos.logback.classic.Logger)logger if (!rootLogger.iteratorForAppenders().hasNext()) { try { // previous test wiped out the logging config bring it back for the next test @@ -305,11 +309,10 @@ abstract class AgentTestRunner extends DDSpecification implements AgentBuilder.L } rootLogger.setLevel(Level.WARN) - ((Logger) LoggerFactory.getLogger("datadog")).setLevel(Level.DEBUG) - ((Logger) LoggerFactory.getLogger("org.testcontainers")).setLevel(Level.DEBUG) + ((ch.qos.logback.classic.Logger) LoggerFactory.getLogger("datadog")).setLevel(Level.DEBUG) + ((ch.qos.logback.classic.Logger) LoggerFactory.getLogger("org.testcontainers")).setLevel(Level.DEBUG) } - def codeOriginSetup() { injectSysConfig(CODE_ORIGIN_FOR_SPANS_ENABLED, "true", true) injectSysConfig(DYNAMIC_INSTRUMENTATION_VERIFY_BYTECODE, "false", true) diff --git a/gradle/slf4j-simple.gradle b/gradle/slf4j-simple.gradle new file mode 100644 index 00000000000..a83ef57a71a --- /dev/null +++ b/gradle/slf4j-simple.gradle @@ -0,0 +1,27 @@ +// Apply this script when `slf4j-simple` should be used instead of `logback`. + +configurations.configureEach { cfg -> + def name = cfg.name + + if (name.containsIgnoreCase("test")) { + // Exclude Logback from all test-like runtimeClasspath configurations. + if (name.endsWithIgnoreCase("runtimeClasspath")) { + cfg.exclude group: "ch.qos.logback" + } + + // Add slf4j-simple to all test-like runtimeOnly configurations. + if (name.endsWithIgnoreCase("runtimeOnly")) { + project.dependencies.add(name, "org.slf4j:slf4j-simple:${libs.versions.slf4j.get()}") + } + } +} + +// Configure `slf4j-simple` logger. +tasks.withType(Test).configureEach { + jvmArgs += [ + "-Dorg.slf4j.simpleLogger.defaultLogLevel=debug", + "-Dorg.slf4j.simpleLogger.showThreadName=true", + "-Dorg.slf4j.simpleLogger.showDateTime=true", + "-Dorg.slf4j.simpleLogger.dateTimeFormat=HH:mm:ss.SSS" + ] +}