Skip to content

Commit

Permalink
Fix disabling virtual thread context propagation (#10881)
Browse files Browse the repository at this point in the history
  • Loading branch information
laurit committed Mar 18, 2024
1 parent dea9ff7 commit e38093c
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ public static void enablePropagation() {
propagationDisabled.remove();
}

private static boolean isPropagationDisabled() {
// visible for testing
public static boolean isPropagationDisabled() {
return propagationDisabled.get() != null;
}

Expand Down
7 changes: 6 additions & 1 deletion instrumentation/executors/javaagent/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ dependencies {
bootstrap(project(":instrumentation:executors:bootstrap"))

testImplementation(project(":instrumentation:executors:testing"))

testImplementation("org.scala-lang:scala-library:2.11.12")
testCompileOnly(project(":instrumentation:executors:bootstrap"))
}

testing {
Expand All @@ -29,6 +29,7 @@ testing {

dependencies {
implementation(project(":instrumentation:executors:testing"))
compileOnly(project(":instrumentation:executors:bootstrap"))
}

targets {
Expand All @@ -44,6 +45,10 @@ testing {

tasks {
withType<Test>().configureEach {
// needed for VirtualThreadTest on jdk21
jvmArgs("--add-opens=java.base/java.lang=ALL-UNNAMED")
jvmArgs("-XX:+IgnoreUnrecognizedVMOptions")

jvmArgs(
"-Dotel.instrumentation.executors.include=io.opentelemetry.javaagent.instrumentation.executors.ExecutorInstrumentationTest\$CustomThreadPoolExecutor,io.opentelemetry.javaagent.instrumentation.executors.ThreadPoolExecutorTest\$RunnableCheckingThreadPoolExecutor"
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.executors;

import static org.assertj.core.api.Assertions.assertThat;

import io.opentelemetry.javaagent.bootstrap.executors.ExecutorAdviceHelper;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledForJreRange;
import org.junit.jupiter.api.condition.JRE;

@EnabledForJreRange(min = JRE.JAVA_21)
class VirtualThreadTest {

@Test
void testDisableContextPropagation() throws Exception {
TestRunnable testRunnable = new TestRunnable();
// Thread.ofVirtual().start(testRunnable);
Method ofVirtualMethod = Thread.class.getMethod("ofVirtual");
Object virtualThreadBuilder = ofVirtualMethod.invoke(null);
Method startVirtualThread =
Class.forName("java.lang.Thread$Builder").getMethod("start", Runnable.class);
Thread thread = (Thread) startVirtualThread.invoke(virtualThreadBuilder, testRunnable);
thread.join();

assertThat(testRunnable.error).isNull();
assertThat(testRunnable.isPropagationDisabled.get()).isTrue();
}

private static void executeOnCarrierThread(Callable<?> callable) throws Exception {
// call VirtualThread.executeOnCarrierThread, VirtualThreadInstrumentation disables context
// propagation inside that method
Method executeOnCarrierThreadMethod =
Class.forName("java.lang.VirtualThread")
.getDeclaredMethod("executeOnCarrierThread", Callable.class);
executeOnCarrierThreadMethod.setAccessible(true);
executeOnCarrierThreadMethod.invoke(Thread.currentThread(), callable);
}

static class TestRunnable implements Runnable {
AtomicBoolean isPropagationDisabled = new AtomicBoolean();
Exception error;

@Override
public void run() {
try {
executeOnCarrierThread(
() -> {
isPropagationDisabled.set(ExecutorAdviceHelper.isPropagationDisabled());
return null;
});
} catch (Exception exception) {
error = exception;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ private static void configureIgnoredTypes(IgnoredTypesBuilder builder) {
// java.lang.ClassCircularityError: java/lang/ClassLoader$1
// when SecurityManager is enabled. ClassLoader$1 is used in ClassLoader.checkPackageAccess
.ignoreClass("java.lang.ClassLoader$")
.allowClass("java.lang.VirtualThread")
.allowClass("java.lang.invoke.InnerClassLambdaMetafactory")
// Concurrent instrumentation modifies the structure of
// Cleaner class incompatibly with java9+ modules.
Expand Down

0 comments on commit e38093c

Please sign in to comment.