diff --git a/instrumentation/graphql-java/graphql-java-20.0/javaagent/build.gradle.kts b/instrumentation/graphql-java/graphql-java-20.0/javaagent/build.gradle.kts index 72b8aa95c2f7..e2fbbac15a29 100644 --- a/instrumentation/graphql-java/graphql-java-20.0/javaagent/build.gradle.kts +++ b/instrumentation/graphql-java/graphql-java-20.0/javaagent/build.gradle.kts @@ -22,3 +22,9 @@ dependencies { testImplementation(project(":instrumentation:graphql-java:graphql-java-common:testing")) } + +if (findProperty("testLatestDeps") as Boolean) { + otelJava { + minJavaVersionSupported.set(JavaVersion.VERSION_11) + } +} diff --git a/instrumentation/graphql-java/graphql-java-20.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v20_0/GraphqlInstrumentation.java b/instrumentation/graphql-java/graphql-java-20.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v20_0/GraphqlInstrumentation.java index 4e652617506f..07b891bd52f2 100644 --- a/instrumentation/graphql-java/graphql-java-20.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v20_0/GraphqlInstrumentation.java +++ b/instrumentation/graphql-java/graphql-java-20.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v20_0/GraphqlInstrumentation.java @@ -7,15 +7,25 @@ import static io.opentelemetry.javaagent.instrumentation.graphql.v20_0.GraphqlSingletons.addInstrumentation; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; -import static net.bytebuddy.matcher.ElementMatchers.returns; +import static net.bytebuddy.matcher.ElementMatchers.none; +import com.google.errorprone.annotations.CanIgnoreReturnValue; import graphql.execution.instrumentation.Instrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import net.bytebuddy.asm.Advice; +import net.bytebuddy.asm.AsmVisitorWrapper; +import net.bytebuddy.description.field.FieldDescription; +import net.bytebuddy.description.field.FieldList; +import net.bytebuddy.description.method.MethodList; import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.implementation.Implementation; import net.bytebuddy.matcher.ElementMatcher; +import net.bytebuddy.pool.TypePool; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; class GraphqlInstrumentation implements TypeInstrumentation { @@ -27,15 +37,78 @@ public ElementMatcher typeMatcher() { @Override public void transform(TypeTransformer transformer) { transformer.applyAdviceToMethod( - namedOneOf("checkInstrumentationDefaultState", "checkInstrumentation") - .and(returns(named("graphql.execution.instrumentation.Instrumentation"))), - this.getClass().getName() + "$AddInstrumentationAdvice"); + none(), this.getClass().getName() + "$AddInstrumentationAdvice"); + + transformer.applyTransformer( + (builder, typeDescription, classLoader, javaModule, protectionDomain) -> + builder.visit( + new AsmVisitorWrapper() { + @Override + public int mergeWriter(int flags) { + return flags; + } + + @Override + @CanIgnoreReturnValue + public int mergeReader(int flags) { + return flags; + } + + @Override + public ClassVisitor wrap( + TypeDescription instrumentedType, + ClassVisitor classVisitor, + Implementation.Context implementationContext, + TypePool typePool, + FieldList fields, + MethodList methods, + int writerFlags, + int readerFlags) { + return new ClassVisitor(Opcodes.ASM9, classVisitor) { + @Override + public MethodVisitor visitMethod( + int access, + String name, + String descriptor, + String signature, + String[] exceptions) { + MethodVisitor mv = + super.visitMethod(access, name, descriptor, signature, exceptions); + if ("".equals(name) + && "(Lgraphql/GraphQL$Builder;)V".equals(descriptor)) { + return new MethodVisitor(api, mv) { + @Override + public void visitFieldInsn( + int opcode, String owner, String name, String descriptor) { + // Call GraphqlSingletons.addInstrumentation on the value before it is + // written to the instrumentation field + if (opcode == Opcodes.PUTFIELD + && "instrumentation".equals(name) + && "Lgraphql/execution/instrumentation/Instrumentation;" + .equals(descriptor)) { + mv.visitMethodInsn( + Opcodes.INVOKESTATIC, + Type.getInternalName(GraphqlSingletons.class), + "addInstrumentation", + "(Lgraphql/execution/instrumentation/Instrumentation;)Lgraphql/execution/instrumentation/Instrumentation;", + false); + } + super.visitFieldInsn(opcode, owner, name, descriptor); + } + }; + } + return mv; + } + }; + } + })); } @SuppressWarnings("unused") public static class AddInstrumentationAdvice { @Advice.OnMethodExit(suppress = Throwable.class) public static void onExit(@Advice.Return(readOnly = false) Instrumentation instrumentation) { + // this advice is here only to get GraphqlSingletons injected and checked by muzzle instrumentation = addInstrumentation(instrumentation); } } diff --git a/instrumentation/graphql-java/graphql-java-20.0/library/build.gradle.kts b/instrumentation/graphql-java/graphql-java-20.0/library/build.gradle.kts index 6537286f62c2..79f49cf21985 100644 --- a/instrumentation/graphql-java/graphql-java-20.0/library/build.gradle.kts +++ b/instrumentation/graphql-java/graphql-java-20.0/library/build.gradle.kts @@ -8,3 +8,9 @@ dependencies { testImplementation(project(":instrumentation:graphql-java:graphql-java-common:testing")) } + +if (findProperty("testLatestDeps") as Boolean) { + otelJava { + minJavaVersionSupported.set(JavaVersion.VERSION_11) + } +}